简介:
Android 8.0(API 级别 26)引入了自适应启动器图标,它可以在不同设备型号上显示为不同的形状。例如,在一台原始设备制造商 (OEM) 设备上,自适应启动器图标可显示为圆形,而在其他设备上则可显示为方圆形。
异常:
使用 Jetpack Compose 时,我们有时需要显示自己应用的图标或其他应用的图标。
如果我们的应用支持自适应图标,直接使用 painterResource
加载图标时就会抛出 IllegalArgumentException
异常:
IllegalArgumentException: Only VectorDrawables and rasterized asset types are supported ex. PNG, JPG
代码:
Image(painter = painterResource(R.mipmap.ic_launcher), contentDescription = null)
异常:
AndroidRuntime: FATAL EXCEPTION: main
Process: cn.itmob.demo, PID: 5021
java.lang.IllegalArgumentException: Only VectorDrawables and rasterized asset types are supported ex. PNG, JPG
at androidx.compose.ui.res.PainterResources_androidKt.loadVectorResource(PainterResources.android.kt:93)
at androidx.compose.ui.res.PainterResources_androidKt.painterResource(PainterResources.android.kt:65)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:39)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:31)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material3.SurfaceKt$Surface$6.invoke(Surface.kt:261)
at androidx.compose.material3.SurfaceKt$Surface$6.invoke(Surface.kt:252)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material3.SurfaceKt.Surface-ZaiARg4(Surface.kt:249)
at androidx.compose.material3.SurfaceKt.Surface-T9BRK9s(Surface.kt:109)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-2$1.invoke(MainActivity.kt:26)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-2$1.invoke(MainActivity.kt:24)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material3.TextKt.ProvideTextStyle(Text.kt:261)
at androidx.compose.material3.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:71)
at androidx.compose.material3.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:70)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material3.MaterialThemeKt.MaterialTheme(MaterialTheme.kt:66)
at cn.itmob.demo.ui.theme.ThemeKt.DemoTheme(Theme.kt:63)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-3$1.invoke(MainActivity.kt:24)
at cn.itmob.demo.ComposableSingletons$MainActivityKt$lambda-3$1.invoke(MainActivity.kt:23)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:410)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:252)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:251)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:166)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:123)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:122)
解决这个异常就需要使用其他方式加载应用图标,使用 PackageManager
加载应用图标,或使用 ResourcesCompat
直接加载自适应图标资源。
方法一:
使用 PackageManager
获取应用图标:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTextDemoTheme {
Surface(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
color = MaterialTheme.colorScheme.background
) {
Column(verticalArrangement = Arrangement.Center) {
getAppIconBitmap(packageName)?.let {
Image(bitmap = it.asImageBitmap(), contentDescription = null)
}
}
}
}
}
}
private fun getAppIconBitmap(packageName: String): Bitmap? {
return try {
packageManager.let { packageManager ->
packageManager.getLaunchIntentForPackage(packageName)?.let {
packageManager.getActivityIcon(it)
} ?: packageManager.getApplicationIcon(packageName)
}
} catch (e: PackageManager.NameNotFoundException) {
getDrawable(android.R.drawable.sym_def_app_icon)
}.let {
it?.toBitmap()
}
}
}
方法二:
使用 ResourceCompat
直接获取应用资源
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTextDemoTheme {
Surface(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
color = MaterialTheme.colorScheme.background
) {
Column(verticalArrangement = Arrangement.Center) {
getAppIconBitmap()?.let {
Image(bitmap = it.asImageBitmap(), contentDescription = null)
}
}
}
}
}
}
private fun getAppIconBitmap(): Bitmap? {
return ResourcesCompat.getDrawable(
resources,
R.mipmap.ic_launcher,
theme
)?.let { drawable ->
Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
).apply {
val canvas = Canvas(this)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
}
}
}
}