集成ViewModel与Dialog后Android应用持续崩溃,求排查解决
山羊养殖场追踪应用Dialog+ViewModel集成崩溃问题修复
我开发了一个山羊养殖场信息追踪的新项目,这是我首次为弹窗Dialog使用ViewModel,推测问题出在此处——在集成ViewModel和Dialog之前,应用运行流畅。当前Gradle构建无报错,但应用频繁崩溃。
核心问题分析
代码中存在一个致命的ViewModel使用错误:在GoatList的列表循环里,每次渲染GoatCard时都手动实例化了MainViewModel()。这会导致:
- 每个列表项持有独立的ViewModel实例,状态无法统一管理
- 手动创建的ViewModel不受Jetpack生命周期框架管控,引发生命周期相关崩溃
- LazyGrid复用列表项时,ViewModel频繁创建销毁,进一步加剧崩溃概率
同时,Activity中初始化的ViewModel没有传递到Composable层级,状态管理链路完全断裂。
修复后的完整代码
1. MainActivity 调整
将Activity中获取的ViewModel传递给根Composable:
class MainActivity : AppCompatActivity() { private val viewModel by viewModels<MainViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { GoatsTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { GoatsApp(viewModel = viewModel) } } } } }
2. GoatsApp 调整
接收ViewModel并向下传递给列表组件:
@Composable fun GoatsApp(viewModel: MainViewModel) { val provider = GoogleFont.Provider( providerAuthority = "com.google.android.gms.fonts", providerPackage = "com.google.android.gms", certificates = R.array.com_google_android_gms_fonts_certs ) val fontName = GoogleFont("Lato") val fontFamily = FontFamily( Font(googleFont = fontName, fontProvider = provider) ) Column(modifier = Modifier.padding(16.dp)) { Text(text = "Does", modifier = Modifier .background(color = Color.LightGray) .fillMaxWidth() .padding(12.dp), fontStyle = FontStyle.Italic, textAlign = TextAlign.Center, fontFamily = fontFamily, fontWeight = FontWeight.ExtraLight ) GoatList(goatList = DataSource.goats, viewModel = viewModel, modifier = Modifier.padding(8.dp)) } }
3. GoatList 调整
接收ViewModel并传递给单个卡片组件,禁止手动实例化ViewModel:
@Composable fun GoatList(goatList: List<Goats>, viewModel: MainViewModel, modifier: Modifier = Modifier.padding(8.dp)) { LazyVerticalGrid(columns = GridCells.Fixed(1), modifier.padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { items(goats) { allgoats -> GoatCard(allgoats = allgoats, viewModel = viewModel) } } }
4. GoatCard 保持不变(仅接收ViewModel参数)
@Composable fun GoatCard(allgoats: Goats, viewModel: MainViewModel) { val years = allgoats.age.toString() Card(modifier = Modifier) { Row{ Image(painter = painterResource(allgoats.image), contentDescription = allgoats.name.toString(), modifier = Modifier.size(68.dp), contentScale = ContentScale.Crop) Column(Modifier.width(120.dp)) { Text(text = stringResource(allgoats.name), modifier = Modifier.padding(8.dp), style = MaterialTheme.typography.titleSmall) Row{ Text(text = stringResource(allgoats.breed), modifier = Modifier.padding(8.dp), style = MaterialTheme.typography.bodySmall) Text(years, modifier = Modifier.padding(8.dp), style = MaterialTheme.typography.bodySmall) Box { Button(onClick = { viewModel.isGoatClick() }, modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(Color.LightGray)) { } Text(text = "More", style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.End, fontWeight = FontWeight.Bold, modifier = Modifier .fillMaxWidth() .padding(end = 6.dp, top = 12.dp)) } } if(viewModel.isDialogShown) { CustomDialog(onDismiss = { viewModel.onDismissDialog() }, myGoats = Goats(name = allgoats.name, age = allgoats.age, breed = allgoats.breed, image = allgoats.image)) } } } } }
5. MainViewModel 保持不变
import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel class MainViewModel : ViewModel() { var isDialogShown by mutableStateOf(false) private set fun isGoatClick() { isDialogShown = true } fun onDismissDialog() { isDialogShown = false } }
更简洁的实现方式
可以直接在Composable中使用viewModel()函数获取ViewModel,无需从Activity传递,代码更简洁:
@Composable fun GoatsApp() { val viewModel: MainViewModel = viewModel() // 剩余代码与之前一致 }
对应的MainActivity简化为:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { GoatsTheme { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { GoatsApp() } } } } }
内容的提问来源于stack exchange,提问作者vukica
相关产品推荐
相关产品推荐

