如何从 kotlin Android 中的其他文件访问 MainActivity 中的值

how to access the value in MainActivity from other file in kotlin Android

提问人:M Baig 提问时间:10/5/2023 更新时间:10/5/2023 访问量:38

问:

我已经在MainActivity中创建了一个数据库,并且需要另一个类中的数据库实例,但是它给出了此错误

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 -> this is line where the above error is showing
    //  val databaseItems by database.menuItemDao().getAll().observeAsState(emptyList())

此行返回 MainActivity 中的值,但我想在此文件中使用它,它返回 null 指针异常。我可以更改什么才能使其正常工作?谢谢。val databaseItems by database.menuItemDao().getAll().observeAsState(emptyList())

Android Kotlin NullPointerException

评论


答:

0赞 Vinny_Vl 10/5/2023 #1

您不能只调用 MainActivity 构造函数,您尝试访问数据库的方式是错误的。至少你应该使用一些 ViewModel 来存储你的数据库类。但是在你的情况下,你可以把数据库实例放在某个对象中,就像这样:

object DatabaseStorage {

    var databaseInstance: YourDatabaseClass? = null
}

class MainActivity {

    val database by lazy {
        Room.databaseBuilder(applicationContext,AppDatabase::class.java,"database").build()
    }

   override fun onCreate(...) {

        DatabaseStorage.databaseInstance = database
    }
}

// and in your fun
@Composable
fun Piece() {
    val databaseInstance = DatabaseStorage.databaseInstance 
}

但是这种方法确实很糟糕,你应该使用一些DI库,并且只在数据层直接使用你的数据库。您可以阅读本文以获得更好的解决方案 https://proandroiddev.com/news-android-app-607f9dc6a3d1

0赞 Kristy Welsh 10/5/2023 #2

首先,你不应该将数据库传递给你的可组合项。标准架构模式是为应用创建一个存储库,并让 viewModel 完成与数据库的所有连接,然后你可以从中返回流。

像这样:

class myDatabase {
     lateinit var dataBase: AppDatabase
     val dao = MyDatabaseDao()

     fun build(context: Context) {
     database = Room.databaseBuilder(context,AppDatabase::class.java,"database").build()
     }
}

class myApplication: Application { 
    override onCreate { 
        MyDatabase().build()
}

interface MyDatabaseRepo { 
    fun grabDataFromDatabase()
}

class MyDatabaseRepoImpl: MyDatabaseRepo { 
    val myDao = MyDatabase().dao

    override fun grabDataFromDatabase() { 
        myDao.doSomething()
    }
                 
}


class myViewModel(databaseRepo: MyDatabaseRepo): ViewModel() { 
    
    val myStateFlow = MutableStateFlow(listOf<Int>()) 

    fun grabData() {
       myStateFlow.update { databaseRepo.grabSomthingFromDatabase()}
    }

}

@Composable
fun Piece(viewModel:MyViewModel) { 
     val data = viewModel.myStateFlow.collectAsState()

}

但正如 Vinny 所说,你可能应该使用一些依赖注入来使它变得非常干净。这会给你很大的自由。我推荐koin,因为它是最容易学习的。