崩潰原因分析
// 錯誤 1:Context 可能是 Application,非 Activity
Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
// ClassCastException: android.app.Application cannot be cast to android.app.Activity
// 錯誤 2:getSize(Point) 是 API 13 (Android 3.2) 新增
display.getSize(size); // 低版本編譯報錯或運行時崩潰
修正方案一:安全獲取 WindowManager(不依賴 Activity)
// 任何 Context 均可
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
修正方案二:兼容低版本獲取尺寸
Point size = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { // API 13
display.getSize(size);
} else {
// 舊 API
size.x = display.getWidth(); // deprecated
size.y = display.getHeight(); // deprecated
}
int width = size.x;
int height = size.y;
現代最佳實踐:Resources 或 DisplayMetrics
// 方案 A:Resources(最簡單,無需 Context 類型轉換)
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int width = metrics.widthPixels;
int height = metrics.heightPixels;
float density = metrics.density; // dp/px 比例
int densityDpi = metrics.densityDpi;
// 方案 B:WindowMetrics (API 30+,支援多窗口、分屏)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
Insets insets = windowMetrics.getWindowInsets()
.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout());
Rect bounds = windowMetrics.getBounds();
// 可用區域寬高
int usableWidth = bounds.width() - insets.left - insets.right;
int usableHeight = bounds.height() - insets.top - insets.bottom;
}
總結
- 不要強轉 Context 為 Activity,用
context.getSystemService(WINDOW_SERVICE)。
Display.getSize() 需 API 13+,舊版用 getWidth()/getHeight()。
- **首選
Resources.getDisplayMetrics()**,最穩健、無版本兼容問題、不依賴 WindowManager。
- 多窗口/分屏場景 (API 30+) 必須用
WindowMetrics 獲取實際可用區域。