Android跨API版本获取宽高仍遇废弃警告:问题排查与解决
我参考Stack Overflow相关问题后,编写了适配Android API level >=30和API level <30的屏幕宽高获取代码,代码如下:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val backgroundThread = Thread { val metric: WindowMetrics val insets: Insets // An Insets instance holds four integer offsets which describe changes to the four edges of a Rectangle. val displayMetrics: DisplayMetrics val width: Int val height: Int val insetsWidth: Int val insetsHeight: Int if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Code for API level 30 and higher metric = windowManager.currentWindowMetrics insets = windowManager.currentWindowMetrics.windowInsets.getInsetsIgnoringVisibility (WindowInsets.Type.navigationBars() or WindowInsets.Type.displayCutout ()) insetsWidth = insets.right + insets.left insetsHeight = insets.top + insets.bottom Log.d ("tally", "${insets.right}, ${insets.left}, ${insets.top}, ${insets.bottom}") width = metric.bounds.width () - insetsWidth height = metric.bounds.height () - insetsHeight } else { displayMetrics = DisplayMetrics () windowManager.defaultDisplay.getMetrics (displayMetrics) width = displayMetrics.widthPixels height = displayMetrics.heightPixels } } backgroundThread.start() } /** * A native method that is implemented by the 'dpi_poc' native library, * which is packaged with this application. */ external fun stringFromJNI(): String companion object { // Used to load the 'dpi_poc' library on application startup. init { System.loadLibrary("dpi_poc") } } }
尽管已通过if-else分支区分不同API版本的实现,但仍收到废弃警告,请问代码存在什么问题?如何解决该警告并实现跨API版本的屏幕宽高获取?
问题原因
出现废弃警告的核心原因是Lint静态代码检测不区分运行时分支:你在else分支中调用的WindowManager.DefaultDisplay.getMetrics()方法在API 30+已被标记为废弃,Lint只要检测到代码中存在该调用,就会触发警告——哪怕你已经通过Build.VERSION.SDK_INT做了版本判断,确保低版本才会执行这段代码。
另外,代码中把所有变量都声明在if-else分支外部,虽然语法上合法(if-else覆盖了所有赋值路径),但会导致变量作用域不合理,也增加了代码冗余性。
解决方法
1. 忽略废弃警告(安全且简单)
在包含废弃方法调用的代码块或方法上添加@Suppress("DEPRECATION")注解,明确告诉Lint你已经知晓该方法废弃,且通过版本判断保证了调用的安全性。
2. 优化变量作用域
将变量声明移到对应的分支内部,避免不必要的全局声明,让代码逻辑更清晰,同时减少潜在的编译警告。
3. 统一宽高获取逻辑(可选)
低版本的getMetrics()获取的是屏幕整体尺寸(包含系统导航栏等),而高版本代码中你减去了导航栏和刘海的Insets,得到的是应用可用区域。如果需要统一逻辑,低版本可以通过View.getWindowVisibleDisplayFrame()获取可用区域;如果需求就是获取屏幕整体尺寸,可保持现有逻辑。
修改后的代码示例
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val backgroundThread = Thread { val width: Int val height: Int if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // API 30+ 逻辑 val metric = windowManager.currentWindowMetrics val insets = metric.windowInsets.getInsetsIgnoringVisibility( WindowInsets.Type.navigationBars() or WindowInsets.Type.displayCutout() ) val insetsWidth = insets.right + insets.left val insetsHeight = insets.top + insets.bottom Log.d("tally", "${insets.right}, ${insets.left}, ${insets.top}, ${insets.bottom}") width = metric.bounds.width() - insetsWidth height = metric.bounds.height() - insetsHeight } else { // API <30 逻辑,添加注解忽略废弃警告 @Suppress("DEPRECATION") val displayMetrics = DisplayMetrics().apply { windowManager.defaultDisplay.getMetrics(this) } width = displayMetrics.widthPixels height = displayMetrics.heightPixels } // 此处可使用获取到的width和height执行后续操作 } backgroundThread.start() } external fun stringFromJNI(): String companion object { init { System.loadLibrary("dpi_poc") } } }
额外说明
- 若项目使用AndroidX Core库,可考虑用
WindowInsetsCompat统一处理Insets,进一步简化跨版本适配逻辑,但上述方案已能解决核心问题。 - 确保在非UI线程中执行屏幕尺寸获取时,不涉及UI操作(你的代码已用Thread处理,这部分合理)。
内容的提问来源于stack exchange,提问作者Jatin guglani

