kotlin.KotlinNullPointerException 从本地房间数据库访问数据时?

kotlin.KotlinNullPointerException while accessing Data from local Room Database?

我是 Kotlin 的新手,正在尝试学习如何通过改造获取数据并将这些数据存储到 Room DB 中。但是,一旦我开始执行此过程的 Activity,我就会收到 NullPointerException。

编辑:据我所知,我在 RoomViewmodel class 中的 "database" 在我想访问它时仍然是 NULL,即使我有一个覆盖 oncreate 函数,其中它已创建

这里还有一个 link 来自我正在处理的迷你项目的 GitHub 存储库:https://github.com/Engin92/Dog_Breeds/tree/RoomDatabase

这是我的完整错误列表:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.dogbreeds, PID: 14803
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.dogbreeds/com.example.Breedlist.activity.DetailedViewActivity}: kotlin.KotlinNullPointerException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3961)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2386)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:8178)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
     Caused by: kotlin.KotlinNullPointerException
        at com.example.Breedlist.activity.DetailedViewActivityRepository.getBreeds(DetailedViewActivityRepository.kt:23)
        at com.example.Breedlist.activity.DetailedViewActivityViewModel.getAllBreedList(DetailedViewActivityViewModel.kt:23)
        at com.example.Breedlist.activity.DetailedViewActivity.onCreate(DetailedViewActivity.kt:42)
        at android.app.Activity.performCreate(Activity.java:8086)
        at android.app.Activity.performCreate(Activity.java:8074)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1313)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3755)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3961) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2386) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:213) 
        at android.app.ActivityThread.main(ActivityThread.java:8178) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101) 

DetailedView的重要部分Activity

class DetailedViewActivity : AppCompatActivity() {

    lateinit var breedRecyclerView: RecyclerView
    lateinit var detailedViewActivityViewModel: DetailedViewActivityViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detailed_view)

        breedRecyclerView = findViewById(R.id.breedRecyclerView)

        detailedViewActivityViewModel = ViewModelProviders.of(this).get(
            DetailedViewActivityViewModel::class.java)


        if(isOnline(this))
        {
            detailedViewActivityViewModel.getBreedsFromAPIAndStore()
        }
        else
        {
            Toast.makeText(this,"No internet connection. Showing cached list!",Toast.LENGTH_LONG).show()
        }

        detailedViewActivityViewModel.getAllBreedList().observe(this, Observer<List<CurrentBreedResponseItem>> { breedList ->
            Log.e(MainActivity::class.java.simpleName,breedList.toString())
            setUpBreedRecyclerView(breedList!!)
        })
    } ....

class RoomViewModel,我在其中构建数据库(我认为错误在于,在尝试访问 (write/read) 之后,var 数据库仍然为 NULL)

class RoomViewModel : Application() {

    companion object {
        var database: BreedDatabase? = null
    }

    override fun onCreate() {
        super.onCreate()
        database =  Room.databaseBuilder(applicationContext, BreedDatabase::class.java, "breed_db").fallbackToDestructiveMigration().build()
    }
}

DetailedView 中的 getBreeds 函数Activity存储库:

fun getBreeds() : LiveData<List<CurrentBreedResponseItem>>
{
    return RoomViewModel.database!!.currentBreedDao().getAllBreeds()
}

DetailedViewActivityViewModel

中的 getAllBreedList 函数
fun getAllBreedList(): LiveData<List<CurrentBreedResponseItem>>
{
    return detailedViewActivityRepository.getBreeds()
}

你的代码有两个问题。第一个非常清楚,您正在尝试访问一个空对象,并且您得到了 NullPointerException。所以在使用 !! 运算符时要小心。

您得到它的原因是,在您的 RoomViewModel 中,您的数据库实例为空。

class RoomViewModel : Application() {

    companion object {
        var database: BreedDatabase? = null
    }

    override fun onCreate() {
        super.onCreate()
        database = Room.databaseBuilder(applicationContext, BreedDatabase::class.java, "breed_db")
            .fallbackToDestructiveMigration().build()
    }
}

您可能认为您正在 onCreate() 中初始化数据库实例,但 onCreate() 没有被调用。原因是要使应用程序 class 正常工作,您需要将其添加到 AndroidManifest.xml 文件中。

解法:

像这样将 RoomViewModel class 添加到您的 AndroidManifest.xml 文件中。

<application
    android:name=".view.RoomViewModel"
    android:allowBackup="true" 

如上所示,我们将其作为应用程序标签的名称属性来实现。 这将修复您的空指针异常。但是你的程序会再次崩溃,因为你正在使用 Kotlin 并且确实需要在你的应用程序级别 build.gradle 文件中添加这个东西。

kapt "android.arch.persistence.room:compiler:1.1.1"

将其添加到依赖项块内的应用级别 build.gradle 后。同步您的项目,运行 它应该可以工作。

如果您想在 Android 中了解有关房间数据库的更多信息,可以查看此 Room Database Tutorial

希望这对您有所帮助。