Kotlin Android:跨文件访问MainActivity数据库实例及空指针解决
问题描述
在MainActivity中创建了Room数据库实例,在Compose组件Piece.kt中使用时触发空指针异常:
java.lang.NullPointerException: Attempt to invoke virtual method
'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
MainActivity代码:
class MainActivity : ComponentActivity() { val database by lazy { Room.databaseBuilder(applicationContext,AppDatabase::class.java,"database").build() } @SuppressLint("CoroutineCreationDuringComposition") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val databaseMenuItems by database.menuItemDao().getAll().observeAsState(emptyList()) // } }
Piece.kt中的错误用法:
@Composable fun Piece(){ val mainActivity = MainActivity() val database = mainActivity.database // 此处触发上述错误 // val databaseItems by database.menuItemDao().getAll().observeAsState(emptyList()) }
问题原因
手动new MainActivity()创建的实例并非系统托管的Activity实例,未经过完整初始化流程,applicationContext为空,调用database这个lazy属性时自然触发空指针。
解决方案
方案1:参数传递数据库实例(简单直接)
在MainActivity中调用Piece组件时,直接传入已初始化的数据库实例:
修改MainActivity的setContent代码:
setContent { val databaseMenuItems by database.menuItemDao().getAll().observeAsState(emptyList()) Piece(database = database) // 传入数据库实例 }
修改Piece.kt:
@Composable fun Piece(database: AppDatabase){ val databaseItems by database.menuItemDao().getAll().observeAsState(emptyList()) // 后续使用databaseItems进行UI渲染即可 }
方案2:依赖注入(推荐复杂项目使用)
使用Hilt等依赖注入框架管理Database实例,避免组件间耦合:
- 配置Hilt后,通过
@Provides方法在Module中提供Database实例 - 在MainActivity中注入Database
- 在Compose组件中结合ViewModel或直接注入Database实例(推荐通过ViewModel间接访问,符合MVVM架构)
方案3:通过LocalContext获取Activity实例(不推荐,耦合性高)
如果不想传参,可通过LocalContext获取当前Activity实例,但会强耦合组件与MainActivity:
@Composable fun Piece(){ val context = LocalContext.current val mainActivity = context as? MainActivity ?: return val database = mainActivity.database val databaseItems by database.menuItemDao().getAll().observeAsState(emptyList()) }
内容的提问来源于stack exchange,提问作者M Baig
相关产品推荐
相关产品推荐

