Android Jetpack Compose应用列表滚动卡顿,求优化方案
已安装应用列表滚动卡顿优化方案
核心问题分析
你的代码卡顿主要来自UI线程被耗时操作阻塞和不必要的重组触发,以下是具体优化点及修改后的代码:
优化点1:提前预加载应用图标和名称
info.loadIcon()和info.loadLabel()是耗时的IO/反射操作,直接在LazyColumn列表项中调用会导致滚动时UI线程阻塞。应提前在后台线程加载所有应用的图标和名称,再传递给Compose组件。
优化点2:精简remember的使用逻辑
列表项中的icon和label是静态数据(应用安装后不会实时变化),无需用mutableStateOf存储,只需用remember结合唯一key(如应用包名)缓存即可,避免多余的状态监听。
优化点3:替换自定义Painter为官方实现
官方提供了rememberDrawablePainter(),无需自行实现Painter逻辑,减少自定义代码带来的性能开销。
优化点4:简化复选框点击逻辑
移除外层Box的clickable,直接使用Checkbox的onCheckedChange处理状态切换,避免重复的点击事件处理和重组触发。
优化点5:使用不可变列表避免意外重组
将MutableList<ResolveInfo>改为List<ResolveInfo>,或用mutableStateListOf管理数据,确保Compose仅在数据真正变化时触发重组。
修改后的完整代码
// 先定义封装应用信息的数据类,提前预加载后传入 data class AppInfo( val packageName: String, val icon: Drawable, val label: String ) @Composable fun AppList(appInfoList: List<AppInfo>) { LazyColumn { // 绑定应用包名作为key,提升列表项复用效率 items(items = appInfoList, key = { it.packageName }) { appInfo -> var isChecked by remember { mutableStateOf(false) } // 使用官方DrawablePainter加载图标 val iconPainter = rememberDrawablePainter(appInfo.icon) Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp) ) { Image( painter = iconPainter, contentDescription = appInfo.label, contentScale = ContentScale.Fit, modifier = Modifier .size(48.dp) // 固定图标大小,避免布局重排 .padding(horizontal = 16.dp) ) Text( text = appInfo.label, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f) ) Checkbox( checked = isChecked, onCheckedChange = { isChecked = it }, modifier = Modifier.padding(horizontal = 16.dp) ) } } } } // 预加载应用信息示例(建议在ViewModel中用协程后台执行) fun loadAppInfos(context: Context): List<AppInfo> { val packageManager = context.packageManager val intent = Intent(Intent.ACTION_MAIN, null).apply { addCategory(Intent.CATEGORY_LAUNCHER) } val resolveInfos = packageManager.queryIntentActivities(intent, 0) return resolveInfos.map { info -> AppInfo( packageName = info.activityInfo.packageName, icon = info.loadIcon(packageManager), label = info.loadLabel(packageManager).toString() ) } }
额外性能建议
- 若应用数量极多,可考虑分页加载,避免一次性加载所有数据导致内存压力过大。
- 图标可通过Glide或Coil的Compose扩展进行缓存和压缩,进一步降低内存占用。
内容的提问来源于stack exchange,提问作者124697
相关产品推荐
相关产品推荐

