Android获取视口尺寸时触发java.lang.NoSuchMethodError异常,启动屏背景适配失败求助
解决Android实体设备
getMaximumWindowMetrics()方法找不到异常,实现启动屏适配 问题原因
你遇到的NoSuchMethodError是因为WindowManager.getMaximumWindowMetrics()是Android 11(API级别30)才新增的API,你的实体设备系统版本低于Android 11,所以无法找到这个方法;而模拟器大概率用的是高版本系统,所以能正常运行。
解决方案
下面分两步解决:先修复版本兼容问题,再优化适配逻辑让代码更健壮。
1. 兼容低版本的屏幕尺寸获取
我们需要根据系统版本选择不同的获取方式,在API 30及以上用新方法,低版本用传统的DisplayMetrics方式:
private fun getScreenSize(): Pair<Int, Int> { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11+ 用新API val windowMetrics = windowManager.maximumWindowMetrics val bounds = windowMetrics.bounds bounds.width() to bounds.height() } else { // Android 10及以下 用旧方法 val displayMetrics = DisplayMetrics() windowManager.defaultDisplay.getMetrics(displayMetrics) displayMetrics.widthPixels to displayMetrics.heightPixels } }
然后在onCreate里调用这个方法获取尺寸,替换原来直接调用maximumWindowMetrics的代码即可。
2. 优化启动屏适配逻辑(推荐)
你现在用硬编码尺寸范围的方式非常脆弱——不同设备的屏幕像素可能有细微差异,而且后续新增设备尺寸时要不断修改代码。更推荐用Android原生的资源限定符,让系统自动匹配最合适的启动屏图片:
在
res目录下创建对应屏幕尺寸的drawable子目录,比如:drawable-sw1080dp-h2160dp(对应宽1080dp、高2160dp的设备)drawable-sw1080dp-h2220dpdrawable-sw1440dp-h2880dp- 以此类推,对应你需要适配的所有尺寸
把每个尺寸对应的启动屏图片统一命名为
splashscreen.png,放入对应的目录中最后在布局文件里直接设置背景,不需要任何代码判断:
<androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/constraintLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/splashscreen"> </androidx.constraintlayout.widget.ConstraintLayout>
这样系统会自动根据当前设备的屏幕尺寸选择对应的图片,不仅代码更简洁,适配也更可靠。
完整修正后的代码(兼容版)
如果你暂时不想改用资源限定符,以下是修复了版本兼容问题的完整代码:
package com.example.appName import android.content.Intent import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import android.os.Build import android.util.DisplayMetrics class MainActivity : AppCompatActivity() { private lateinit var constraintLayout: ConstraintLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) supportActionBar?.hide() constraintLayout = findViewById(R.id.constraintLayout) // 兼容不同版本获取屏幕尺寸 val (width, height) = getScreenSize() Log.i("MainActivity", "屏幕尺寸:$width x $height") // 根据尺寸设置背景(建议后续替换为资源限定符方式) when { width in 1075..1085 && height in 2155..2165 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1080x2160) } width in 1075..1085 && height in 2215..2225 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1080x2220) } width in 1075..1085 && height in 2275..2285 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1080x2280) } width in 1275..1285 && height in 1915..1925 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1280x1920) } width in 1435..1445 && height in 2555..2565 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1440x2560) } width in 1435..1445 && height in 2875..2885 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1440x2880) } width in 1435..1445 && height in 2955..2965 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1440x2960) } width in 1435..1445 && height in 3035..3045 -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1440x3040) } else -> { constraintLayout.setBackgroundResource(R.drawable.splashscreen_1280x1920) } } android.os.Handler().postDelayed({ val intent = Intent(this@MainActivity, HomeActivity::class.java) startActivity(intent) finish() }, 3500) } private fun getScreenSize(): Pair<Int, Int> { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val windowMetrics = windowManager.maximumWindowMetrics val bounds = windowMetrics.bounds bounds.width() to bounds.height() } else { val displayMetrics = DisplayMetrics() windowManager.defaultDisplay.getMetrics(displayMetrics) displayMetrics.widthPixels to displayMetrics.heightPixels } } }
内容的提问来源于stack exchange,提问作者Ahmed Anwer
相关产品推荐
相关产品推荐

