如何在 Kotlin 中创建和使用房间数据库 [Dagger-Hilt] [英] How to create and use a Room Database in Kotlin [Dagger-Hilt]

查看:63
本文介绍了如何在 Kotlin 中创建和使用房间数据库 [Dagger-Hilt]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个自我回答的问题,因为我的项目中有代表曝光问题,所以我打算早些时候提出这个问题,但经过几个小时的研究最终解决了这个问题.与其保持沉默,我认为这可能会在未来对某人有所帮助.本教程演示了如何创建 Room 数据库并在活动/片段中使用它.此处给出的示例用例是查询数据库的大小并更新片段中的视图.

This is a self-answered question which I intended to ask earlier as I had rep exposure issues in my project, but ended up fixing it after a couple of hours of research. Instead of staying silent, I thought this might help someone in the future. This tutorial demonstrates how you can create a Room database and use it within an activity/fragment. The example use case given here is querying the size of your database and updating the views in a fragment.

注意:下面的代码中有一些 Dagger-Hilt 依赖注入,但如果您手动执行自己的依赖注入,则应采用相同的方法.我也希望你对 MVVM 架构有一些基本的了解.如果您对涉及 LiveData 的其他方法感兴趣,您可能会在此处找到有用的 Java 相关问题:资源 1资源 2;但是,重点是 Kotlin,并且此解决方案不需要 LiveData.

Note: There is some Dagger-Hilt dependency injection in the code that follows, but the same methodology should apply if you're manually doing your own dependency injection. I also expect that you have some basic knowledge of MVVM architecture. You may find useful Java related questions here if you're interested in other ways to do this involving LiveData: resource 1, resource 2; however, the focus is on Kotlin and this solution doesn't require LiveData.

推荐答案

您必须将项目中的 kotlin 文件关联起来,无论您的项目包的结构如何,但导入应该保持不变.在这种情况下,我使用 Dagger-Hilt 进行依赖注入以避免样板代码.

You'll have to relate the kotlin files in your project for however your project's packages are structured, but the imports should stay the same. In this case, I'm using Dagger-Hilt for dependency injection to avoid boilerplate code.

ItemsYouAreStoringInDB.kt

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "items")
data class ItemsYouAreStoringInDB(/*Parameter of Item entry*/) {
    @PrimaryKey(autoGenerate = true)
    var id: Int? = null
}

YourDao.kt

import androidx.room.*
@Dao
interface YourDAO {
    // Other insertion/deletion/query operations

    @Query("SELECT count(id) FROM items") // items is the table in the @Entity tag of ItemsYouAreStoringInDB.kt, id is a primary key which ensures each entry in DB is unique
    suspend fun numberOfItemsInDB() : Int // suspend keyword to run in coroutine
}

YourDatabase.kt

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(
    entities = [ItemsYouAreStoringInDB::class], // Tell the database the entries will hold data of this type
    version = 1
)

abstract class YourDatabase : RoomDatabase() {

    abstract fun getYourDao(): YourDAO
}

使用 Dagger-Hilt 进行依赖注入,可以创建 YourRepository,因为 Dagger-Hilt 在幕后执行一些操作,通过 YourDatabase 的抽象乐趣 getYourDao() 提供 notificationDaoYourRepository.kt

Using Dagger-Hilt for dependency injection, YourRepository is able to be created as Dagger-Hilt does stuff under the hood to provide a notificationDao via YourDatabase's abstract fun getYourDao() YourRepository.kt

import path.to.ItemsYouAreStoringInDB
import path.to.YourDAO
import javax.inject.Inject // Dagger-Hilt to allow @Inject constructor

class YourRepository @Inject constructor(
    private val yourDAO: YourDAO
){
    // Other functions from YourDao.kt

    suspend fun numberOfItemsInDB() = yourDAO.numberOfItemsInDB()
}

这不是关于如何使用 Dagger-Hilt 的演示,但需要以下两个文件:

This isn't a demonstration on how to use Dagger-Hilt, but the following two files would be necessary:

AppModule.kt

import android.content.Context
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import path.to.YourDatabase

import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Singleton // Tell Dagger-Hilt to create a singleton accessible everywhere in ApplicationCompenent (i.e. everywhere in the application)
    @Provides
    fun provideYourDatabase(
        @ApplicationContext app: Context
    ) = Room.databaseBuilder(
        app,
        YourDatabase::class.java,
        "your_db_name"
    ).build() // The reason we can construct a database for the repo

    @Singleton
    @Provides
    fun provideYourDao(db: YourDatabase) = db.getYourDao() // The reason we can implement a Dao for the database

BaseApplication.kt

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp 
class BaseApplication : Application() {}

您还需要更新 AndroidManifest 文件并选择 BaseApplication 作为应用程序入口点 允许 Android 使用 Dagger-Hilt.

You would also need to update the AndroidManifest file and select the BaseApplication as the application entry point <application android:name="path.to.BaseApplication" ... to allow Android to take advantage of Dagger-Hilt.

继续...

YourViewModel.kt

import dagger.hilt.android.lifecycle.HiltViewModel
import androidx.lifecycle.ViewModel
import path.to.YourRepository

@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: YourRepository
): ViewModel() {
    suspend fun databaseSize() : Int {
        return repository.numberOfItemsInDB()
    }
}

既然您的视图模型可以创建并且可以作为单例在整个应用程序中访问(它的两个实例不能存在),您可以在片段/活动中使用它.视图模型可以访问存储库,该存储库可以通过查询 Room 数据库来接收信息.以下是如何在片段中使用它的示例:

Now that your viewmodel can be created and is accessible throughout the entire application as a singleton (no two instances of it can exist), you can use it in a Fragment/Activity. The viewmodel has access to the repository which can receive information by querying the Room database. Here is an example of how you might use this in a fragment:

YourFragment.kt

@AndroidEntryPoint // Dagger-Hilt requirement
class YourFragment : Fragment(R.layout.fragment_yourFragmentName) {
    private val viewModel: MainViewModel by viewModels()
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setViewsBasedOnRepo() // You might want to call this in onResume()
    }

    private fun setViewsBasedOnRepo() { 
            GlobalScope.launch(Dispatchers.Main) { // Dispatchers.Main because only the Main thread can touch UI elements. Otherwise you may wish to use Dispatchers.IO instead!
                val size  =
                    withContext(Dispatchers.Default) { viewModel.databaseSize() }
                if (size == 0) { // Do stuff based on an empty database
                    btnAddItemsToDB.visibility = View.VISIBLE
                    textViewWarnNoItemsInDB.visibility = View.VISIBLE
                    recyclerViewItems.visibility = View.INVISIBLE
                } else { // Do other stuff when database has entries of type ItemsYouAreStoringInDB
                    btnAddItemsToDB.visibility = View.INVISIBLE                
                    textViewWarnNoItemsInDB.visibility = View.INVISIBLE
                    rvNotifications.visibility = View.VISIBLE
                }
            }
    }
}

这篇关于如何在 Kotlin 中创建和使用房间数据库 [Dagger-Hilt]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆