1. DisplayMetrics基础概念解析在Android开发中DisplayMetrics是一个非常重要的工具类它提供了关于设备显示特性的关键信息。这个类位于android.util包中主要包含以下核心字段widthPixels屏幕的绝对宽度以像素为单位heightPixels屏幕的绝对高度以像素为单位density显示的逻辑密度densityDpi屏幕的DPI每英寸点数scaledDensity显示字体的缩放因子xdpi屏幕X轴方向每英寸精确的物理像素数ydpi屏幕Y轴方向每英寸精确的物理像素数这些参数对于正确适配不同尺寸和密度的Android设备至关重要。在实际开发中我们最常用的是widthPixels和heightPixels来获取屏幕分辨率而density和densityDpi则用于处理屏幕密度相关的适配问题。注意widthPixels和heightPixels获取的是屏幕的原始分辨率不包括系统装饰如状态栏、导航栏占用的空间。如果需要获取应用可用的显示区域应该使用WindowManager获取Display对象后再计算。2. 获取屏幕分辨率的三种方法2.1 通过WindowManager获取这是最常用的方法适用于Activity或Service等有Context的环境WindowManager windowManager (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display windowManager.getDefaultDisplay(); DisplayMetrics metrics new DisplayMetrics(); display.getMetrics(metrics); int width metrics.widthPixels; // 屏幕宽度(px) int height metrics.heightPixels; // 屏幕高度(px) float density metrics.density; // 屏幕密度 int densityDpi metrics.densityDpi; // 屏幕DPI这种方法在Android 4.2及以上版本中会考虑系统UI如导航栏占用的空间。如果需要获取包含系统UI的原始分辨率可以使用getRealMetrics()方法display.getRealMetrics(metrics);2.2 通过Resources获取这种方法适用于任何有Context的环境包括ApplicationDisplayMetrics metrics context.getResources().getDisplayMetrics(); int width metrics.widthPixels; int height metrics.heightPixels;这种方法获取的DisplayMetrics与通过WindowManager获取的基本相同但代码更简洁。需要注意的是它同样不包含被系统UI占用的空间。2.3 通过Configuration获取这种方法适用于需要同时获取屏幕方向等配置信息的情况Configuration config context.getResources().getConfiguration(); DisplayMetrics metrics context.getResources().getDisplayMetrics(); int width config.screenWidthDp * metrics.density; // 转换为px int height config.screenHeightDp * metrics.density; // 转换为px这种方法获取的是以dp为单位的屏幕尺寸需要乘以density转换为像素值。它的特点是会随着屏幕旋转自动调整宽高值。3. 屏幕密度与分辨率的关系3.1 密度无关像素(dp)的概念Android设备有各种屏幕尺寸和像素密度为了确保UI元素在不同设备上显示一致的大小Android引入了密度无关像素dp的概念px dp * (dpi / 160)其中px实际像素数dp密度无关像素dpi每英寸点数屏幕密度DisplayMetrics.density字段实际上就是(dpi / 160)的值因此可以直接用以下方式转换float dp 10; // 10dp float px dp * metrics.density; // 转换为px3.2 常见密度分类Android将屏幕密度分为以下几类密度类型DPI范围缩放因子示例设备ldpi~120dpi0.75x早期低端设备mdpi~160dpi1x基准密度hdpi~240dpi1.5x中端设备xhdpi~320dpi2x主流高端设备xxhdpi~480dpi3x旗舰设备xxxhdpi~640dpi4x超高分辨率设备在实际开发中我们通常使用DisplayMetrics.densityDpi字段来判断当前设备的密度分类switch(metrics.densityDpi) { case DisplayMetrics.DENSITY_LOW: // ldpi设备 break; case DisplayMetrics.DENSITY_MEDIUM: // mdpi设备 break; // 其他case... }4. 多屏幕适配实践技巧4.1 获取正确的可用显示区域在实际应用中我们需要考虑系统UI状态栏、导航栏占用的空间。以下是获取可用显示区域的正确方法Rect rect new Rect(); Window window activity.getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rect); int statusBarHeight rect.top; int contentViewTop window.findViewById(Window.ID_ANDROID_CONTENT).getTop(); int titleBarHeight contentViewTop - statusBarHeight; // 最终可用高度 int availableHeight metrics.heightPixels - statusBarHeight - titleBarHeight;对于全面屏设备还需要考虑刘海屏、挖孔屏等特殊区域if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { WindowInsets windowInsets window.getDecorView().getRootWindowInsets(); if (windowInsets ! null) { DisplayCutout cutout windowInsets.getDisplayCutout(); if (cutout ! null) { // 处理刘海区域 } } }4.2 响应屏幕变化当设备旋转或分屏时屏幕参数会发生变化需要正确处理// 在Activity中重写onConfigurationChanged Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); DisplayMetrics metrics new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); // 更新UI布局 updateLayout(metrics.widthPixels, metrics.heightPixels); }记得在AndroidManifest.xml中声明configChangesactivity android:name.MyActivity android:configChangesorientation|screenSize|screenLayout|smallestScreenSize /activity4.3 高分辨率图片处理对于高DPI设备需要提供相应分辨率的图片资源res/ drawable-ldpi/ icon.png (36x36) drawable-mdpi/ icon.png (48x48) drawable-hdpi/ icon.png (72x72) drawable-xhdpi/ icon.png (96x96) drawable-xxhdpi/ icon.png (144x144) drawable-xxxhdpi/ icon.png (192x192)对于应用图标应该使用mipmap目录res/ mipmap-ldpi/ ic_launcher.png mipmap-mdpi/ ic_launcher.png // 其他密度...5. 常见问题与解决方案5.1 获取的分辨率不正确问题现象在某些设备上获取的widthPixels比实际物理分辨率小。原因分析这可能是因为设备启用了屏幕缩放或虚拟按键占用了部分空间。解决方案使用getRealMetrics()获取物理分辨率检查是否处于多窗口模式考虑虚拟导航栏的高度// 获取物理分辨率 if (Build.VERSION.SDK_INT Build.VERSION_CODES.JELLY_BEAN_MR1) { display.getRealMetrics(metrics); int realWidth metrics.widthPixels; int realHeight metrics.heightPixels; }5.2 屏幕旋转时的布局问题问题现象横竖屏切换时布局错乱。解决方案使用ConstraintLayout等自适应布局为不同方向提供不同的布局资源动态计算控件尺寸// 动态计算ImageView尺寸保持宽高比 imageView.post(() - { int width imageView.getWidth(); int height (int) (width * 0.75); // 4:3比例 imageView.getLayoutParams().height height; imageView.requestLayout(); });5.3 高DPI设备上的性能问题问题现象在高分辨率设备上UI卡顿。原因分析高DPI设备需要渲染更多像素但GPU性能可能跟不上。优化建议减少视图层级使用矢量图代替位图启用硬件加速对复杂视图使用缓存!-- 在AndroidManifest中启用硬件加速 -- application android:hardwareAcceleratedtrue /application6. 高级应用场景6.1 多显示器支持从Android 10开始支持多显示器环境if (Build.VERSION.SDK_INT Build.VERSION_CODES.Q) { Display[] displays displayManager.getDisplays(); for (Display display : displays) { DisplayMetrics metrics new DisplayMetrics(); display.getMetrics(metrics); // 处理每个显示器的参数 } }6.2 动态分辨率切换某些设备支持动态分辨率切换需要监听变化displayManager.registerDisplayListener(new DisplayManager.DisplayListener() { Override public void onDisplayChanged(int displayId) { // 重新获取显示参数 } // 其他方法... }, null);6.3 折叠屏设备适配对于折叠屏设备需要处理屏幕展开/折叠状态变化if (Build.VERSION.SDK_INT Build.VERSION_CODES.N) { configuration.isScreenRound(); // 判断是否为圆形屏幕 } // 监听折叠状态 if (Build.VERSION.SDK_INT Build.VERSION_CODES.R) { windowManager.registerCrossWindowListener(new CrossWindowListener() { Override public void onCrossWindowChanged() { // 处理折叠状态变化 } }); }在实际项目中DisplayMetrics的应用远不止获取屏幕分辨率这么简单。理解其背后的原理和各种使用场景才能写出真正适配各种Android设备的优质应用。建议在开发过程中使用Android Studio的多种虚拟设备进行测试覆盖不同分辨率、密度和形态因素的设备。