如何在 Kotlin [Dagger-Hilt] 中创建和使用房间数据库
Posted
技术标签:
【中文标题】如何在 Kotlin [Dagger-Hilt] 中创建和使用房间数据库【英文标题】:How to create and use a Room Database in Kotlin [Dagger-Hilt] 【发布时间】:2020-11-18 14:43:50 【问题描述】:这是一个自我回答的问题,因为我在项目中遇到了代表曝光问题,但我打算早先提出这个问题,但经过几个小时的研究后最终解决了这个问题。我没有保持沉默,而是认为这可能会在未来帮助某人。本教程演示了如何创建 Room 数据库并在活动/片段中使用它。此处给出的示例用例是查询数据库的大小并更新片段中的视图。
注意:下面的代码中有一些 Dagger-Hilt 依赖注入,但如果您手动执行自己的依赖注入,则应该应用相同的方法。我也希望你对 MVVM 架构有一些基本的了解。如果您对涉及 LiveData 的其他方法感兴趣,您可以在这里找到有用的 Java 相关问题:resource 1、resource 2;但是,重点是 Kotlin,此解决方案不需要 LiveData。
【问题讨论】:
github.com/quicklearner4991/… 【参考方案1】:您必须将项目中的 kotlin 文件关联起来,因为您的项目的包是结构化的,但导入应该保持不变。在这种情况下,我使用 Dagger-Hilt 进行依赖注入以避免样板代码。
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() 提供 notificationDao 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 的演示,但需要以下两个文件:
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 作为应用程序入口点 <application android:name="path.to.BaseApplication" ...
以允许 Android 使用 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()
现在您的视图模型可以作为单例在整个应用程序中创建和访问(不能存在两个实例),您可以在片段/活动中使用它。 viewmodel 可以访问存储库,该存储库可以通过查询 Room 数据库来接收信息。这是一个如何在片段中使用它的示例:
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
【讨论】:
简单性感 我们在哪里使用app模块的provideYourDao和provideYourDatabase函数? @saket 在 Dagger-Hilt 中没有必要使用这些函数。当您构建应用程序时,由于YourRepository.kt
中的@Inject constructor
,将自动创建依赖注入样板代码。因此,在YourRepository.kt
中,您可以使用 Dao 对象与数据库进行交互。同样,YourViewModel.kt 中的 @Inject 允许您访问存储库。然后从 Fragment/Activity 访问 viewModel。我刚刚意识到YourRepository.kt
中的MainRepository
命名错误。为了清楚起见,我将对其进行编辑。
比官方文档好!我认为@ViewModelInject
可能已被@HiltViewModel
+ 标准@Inject
取代:developer.android.com/training/dependency-injection/…
谢谢@charles-allen,你太客气了!我进行了编辑并使用了更贴切的名称@SingletonComponent
而不是@ApplicationComponent
。对于未来的读者,请理解可能存在其他弃用实例,因为这不是官方文档。随意进行编辑或评论。以上是关于如何在 Kotlin [Dagger-Hilt] 中创建和使用房间数据库的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 的表单:如何在 Kotlin 的表单中添加下拉菜单 [重复]