Jetpack Compose不使用ViewModel构建Room应用崩溃求助
问题描述
为学习目的,我在Jetpack Compose中不使用ViewModel构建了一个简易Room应用,但应用出现崩溃情况。以下是相关代码,恳请提供解决建议。
Room数据库代码
@Entity(tableName = "notes") data class Note( @PrimaryKey(autoGenerate = true) val id: Int, val title: String, val content: String ) @Dao interface NoteDao { @Query("SELECT * FROM notes") fun getAllNotes(): List<Note> @Insert fun insert(note: Note): Long } @Database(entities = [Note::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun noteDao(): NoteDao }
MainActivity代码
class MainActivity : ComponentActivity() { private lateinit var db: AppDatabase override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "note-database" ).build() // ... NotesApp(db.noteDao()) // ... } }
NotesApp Composable代码
@Composable fun NotesApp(noteDao: NoteDao) { val notes = remember { mutableStateListOf<Note>() } val title = remember { mutableStateOf("") } val content = remember { mutableStateOf("") } val coroutineScope = rememberCoroutineScope() LaunchedEffect(Unit) { coroutineScope.launch { notes.clear() notes.addAll(noteDao.getAllNotes()) } } Column(modifier = Modifier.fillMaxSize()) { TextField( value = title.value, onValueChange = { title.value = it }, label = { Text("Title") }, modifier = Modifier .fillMaxWidth() .padding(16.dp) ) TextField( value = content.value, onValueChange = { content.value = it }, label = { Text("Content") }, modifier = Modifier .fillMaxWidth() .padding(16.dp) ) Button( onClick = { val newNote = Note(0, title.value, content.value) coroutineScope.launch { noteDao.insert(newNote) notes.clear() notes.addAll(noteDao.getAllNotes()) } }, modifier = Modifier.padding(16.dp) ) { Text("Add Note") } LazyColumn(modifier = Modifier.fillMaxSize()) { items(notes.size) { index -> NoteItem(notes[index]) } } } } @Composable fun NoteItem(note: Note) { Card( modifier = Modifier .fillMaxWidth() .padding(8.dp) ) { Column(modifier = Modifier.padding(16.dp)) { Text(text = note.title, style = MaterialTheme.typography.bodyMedium) Text(text = note.content, style = MaterialTheme.typography.bodySmall) } } }
崩溃原因及修复方案
1. Room操作未在指定线程执行
Room强制要求所有数据库操作必须在非主线程执行,你的DAO方法是同步阻塞式的,直接在协程中调用时,默认调度器可能仍在主线程,触发崩溃。
修复:将DAO方法改为挂起函数,Room会自动处理线程调度:
@Dao interface NoteDao { @Query("SELECT * FROM notes") suspend fun getAllNotes(): List<Note> @Insert suspend fun insert(note: Note): Long }
2. 数据库实例冗余初始化
MainActivity中声明了全局db变量,但又在onCreate内创建了同名局部变量,虽然不直接导致崩溃,但属于冗余代码,统一为:
class MainActivity : ComponentActivity() { private lateinit var db: AppDatabase override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "note-database" ).build() setContent { // 此处添加你的主题配置 NotesApp(db.noteDao()) } } }
3. LaunchedEffect无需嵌套协程
LaunchedEffect本身运行在协程上下文内,不需要额外嵌套coroutineScope.launch,直接调用挂起函数即可:
LaunchedEffect(Unit) { notes.clear() notes.addAll(noteDao.getAllNotes()) }
4. 可选优化:自动监听数据库变化
如果希望列表自动刷新,无需手动重复查询,可将DAO的查询方法改为返回Flow:
@Dao interface NoteDao { @Query("SELECT * FROM notes") fun getAllNotes(): Flow<List<Note>> @Insert suspend fun insert(note: Note): Long }
在Composable中用collectAsState自动收集Flow更新:
@Composable fun NotesApp(noteDao: NoteDao) { val notes by noteDao.getAllNotes().collectAsState(initial = emptyList()) val title = remember { mutableStateOf("") } val content = remember { mutableStateOf("") } val coroutineScope = rememberCoroutineScope() Column(modifier = Modifier.fillMaxSize()) { // TextField部分保持不变 Button( onClick = { val newNote = Note(0, title.value, content.value) coroutineScope.launch { noteDao.insert(newNote) title.value = "" content.value = "" // 可选:清空输入框 } }, modifier = Modifier.padding(16.dp) ) { Text("Add Note") } LazyColumn(modifier = Modifier.fillMaxSize()) { items(notes) { note -> // 直接遍历列表更简洁 NoteItem(note) } } } }
5. 实体类主键默认值优化
给自动生成的主键添加默认值,避免创建实例时必须传0:
@Entity(tableName = "notes") data class Note( @PrimaryKey(autoGenerate = true) val id: Int = 0, // 添加默认值 val title: String, val content: String )
内容的提问来源于stack exchange,提问作者gnoejh
相关产品推荐
相关产品推荐

