{"id":209,"date":"2024-03-19T17:36:32","date_gmt":"2024-03-19T09:36:32","guid":{"rendered":"https:\/\/www.jishuge.cn\/?p=209"},"modified":"2024-03-23T17:12:21","modified_gmt":"2024-03-23T09:12:21","slug":"209","status":"publish","type":"post","link":"https:\/\/blog.jishuge.cn\/?p=209","title":{"rendered":"Android Jetpack Room\u4f7f\u7528\u7684\u5c0f\u7ed3\u3002"},"content":{"rendered":"\n<p><strong>\u6dfb\u52a0\u4f9d\u8d56\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">plugins {\n    id 'com.android.application'\n    id 'kotlin-android'\n    id 'kotlin-kapt' \/\/ \u5982\u679c\u4f7f\u7528Kotlin\uff0c\u9700\u8981kapt\u7f16\u8bd1\u5668\u63d2\u4ef6\n    id 'dagger.hilt.android.plugin' \/\/ Hilt\u63d2\u4ef6\n}\n\ndependencies {\n    implementation 'com.google.dagger:hilt-android:2.40.5' \/\/ Hilt\u6838\u5fc3\u5e93\n    kapt 'com.google.dagger:hilt-compiler:2.40.5' \/\/ \u5982\u679c\u4f7f\u7528Kotlin\uff0c\u9700\u8981kapt\u7f16\u8bd1\u5668\u4f9d\u8d56\n    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0' \/\/ Hilt\u4e0eViewModel\u7684\u96c6\u6210\u5e93\n    implementation 'androidx.room:room-runtime:2.4.3' \/\/ Room\u8fd0\u884c\u65f6\u5e93\n    kapt 'androidx.room:room-compiler:2.4.3' \/\/ \u5982\u679c\u4f7f\u7528Kotlin\uff0c\u9700\u8981kapt\u7f16\u8bd1\u5668\u4f9d\u8d56\n}<\/pre>\n\n\n\n<p>\u4f7f\u7528Room\u7684\u4e09\u4e2a\u6b65\u9aa4\uff1a<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e00\uff0c\u5b9a\u4e49\u6570\u636e\u5e93\uff08AppDatabase\u662f\u81ea\u5b9a\u4e49\u7684\u6570\u636e\u5e93\u7c7b\u540d\u79f0\uff09<\/h3>\n\n\n\n<p>\u5b9a\u4e49\u4e00\u4e2aRoom\u6570\u636e\u5e93\u5b9e\u4f53\uff08\u4f8b\u5982<code>UserEntity<\/code>\uff09\u4ee5\u53ca\u5bf9\u5e94\u7684Room\u6570\u636e\u5e93\u62bd\u8c61\u7c7b\uff08\u4f8b\u5982<code>AppDatabase<\/code>\uff09\uff0c\u5e76\u4f7f\u7528<code>@Database<\/code>\u6ce8\u89e3\u6307\u5b9a\u5305\u542b\u7684\u5b9e\u4f53\u7c7b\u4e0e\u7248\u672c\u4fe1\u606f\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import androidx.room.Database\nimport androidx.room.RoomDatabase\n\n@Database(entities = [UserEntity::class], version = 1)\nabstract class AppDatabase : RoomDatabase() {\n    abstract fun userDao(): UserDao\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e8c\uff0c\u521b\u5efa\u6570\u636e\u7684\u5b9e\u4f53\u7c7b<strong>Entity<\/strong><\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Entity\uff1a\u6ce8\u89e3\u5fc5\u987b\u5b58\u5728\uff0c\u8fd9\u662f\u5b9e\u4f53\u7c7b\u7684\u6807\u5fd7\uff0ctableName \u8868\u540d\n@PrimaryKey\uff1a\u6ce8\u89e3\u8868\u793a\u8fd9\u4e2a\u5b57\u6bb5\u662f\u4e3b\u952e\uff0cautoGenerate\u8868\u793a\u662f\u81ea\u52a8\u589e\u52a0\u7684\n@ColumnInfo\uff1a\u6ce8\u89e3\u8fd9\u4e2a\u5b57\u6bb5\u7684\u522b\u540d\uff0c\u6211\u4eec\u5728\u5176\u4ed6\u5730\u65b9\u5c31\u7528\u8fd9\u4e2a\u522b\u540d\u3002\n\nimport androidx.room.Entity\nimport androidx.room.PrimaryKey\n\n@Entity(tableName = \"users\")\ndata class UserEntity(\n    @PrimaryKey(autoGenerate = true)\n    val id: Int,\n    val name: String,\n    val email: String\n)\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e09\uff0c\u5b9a\u4e49\u4e00\u4e2aData Access Object (DAO) \u63a5\u53e3\uff08\u4f8b\u5982<code>UserDao<\/code>\uff09\uff0c\u5305\u542b\u7528\u4e8e\u66f4\u65b0\u6570\u636e\u7684\u65b9\u6cd5\u7b49<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import androidx.room.Dao\nimport androidx.room.Insert\nimport androidx.room.Query\nimport androidx.room.Update\n\n@Dao\ninterface UserDao {\n    @Update\n    suspend fun updateUser(user: UserEntity)\n\n\n    @Insert\n    suspend fun insertUser(user: UserEntity)\n\n\n    @Query(\"SELECT * FROM users WHERE id=:id \")\n    suspend fun getUserById(id: Int): UserEntity?\n\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u56db\u521b\u5efaRepository<\/h3>\n\n\n\n<p>\u521b\u5efa\u4e00\u4e2aRepository\u7c7b\uff08\u4f8b\u5982<code>UserRepository<\/code>\uff09\uff0c\u5b83\u5c06\u4f5c\u4e3aViewModel\u4e0eRoom\u6570\u636e\u5e93\u4e4b\u95f4\u7684\u4e2d\u4ecb\u3002\u5728\u8fd9\u4e2a\u7c7b\u4e2d\uff0c\u6ce8\u5165<code>UserDao<\/code>\u5e76\u901a\u8fc7\u5176\u65b9\u6cd5\u6267\u884c\u6570\u636e\u66f4\u65b0\u64cd\u4f5c\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class UserRepository @Inject constructor(private val userDao: UserDao) {\n\n    suspend fun updateUser(user: UserEntity) {\n        val data = userDao.getUserById(user.id!!)\n        if (data == null) {\n            userDao.insertUser(user)\n        } else {\n            userDao.updateUser(user)\n        }\n\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>\u7b2c\u4e94\uff1a\u914d\u7f6eHilt Modules<\/strong><\/h3>\n\n\n\n<p>\u521b\u5efa\u4e00\u4e2aHilt\u6a21\u5757\uff08\u4f8b\u5982<code>DatabaseModule<\/code>\uff09\uff0c\u7528\u4e8e\u63d0\u4f9b<code>AppDatabase<\/code>\u5b9e\u4f8b\u3002\u53e6\u5916\uff0c\u53ef\u4ee5\u521b\u5efa\u53e6\u4e00\u4e2a\u6a21\u5757\uff08\u4f8b\u5982<code>RepositoryModule<\/code>\uff09\u6765\u63d0\u4f9b<code>UserRepository<\/code>\u5b9e\u4f8b\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ DatabaseModule.kt\n@Module\n@InstallIn(SingletonComponent::class)\nobject DatabaseModule {\n\n    @Singleton\n    @Provides\n    fun provideDatabase(@ApplicationContext context: Context): AppDatabase {\n        return Room.databaseBuilder(context, AppDatabase::class.java, \"app_database.db\")\n            .build()\n    }\n\n    @Singleton\n    @Provides\n    fun provideUserDao(database: AppDatabase): UserDao {\n        return database.userDao()\n    }\n}\n\n\/\/ RepositoryModule.kt\n@Module\n@InstallIn(SingletonComponent::class)\nobject RepositoryModule {\n\n    @Singleton\n    @Provides\n    fun provideUserRepository(userDao: UserDao): UserRepository {\n        return UserRepository(userDao)\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c<strong>\u516d\uff1aHilt\u5316ViewModel<\/strong><\/h3>\n\n\n\n<p>\u4f7f\u7528<code>@HiltViewModel<\/code>\u6ce8\u89e3\u6807\u8bb0ViewModel\u7c7b\uff08\u4f8b\u5982<code>UserViewModel<\/code>\uff09\uff0c\u5e76\u5728\u5176\u4e2d\u6ce8\u5165\u6240\u9700\u7684<code>UserRepository<\/code>\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ UserViewModel.kt\n@HiltViewModel\nclass UserViewModel @Inject constructor(private val userRepository: UserRepository) : ViewModel() {\n\n    fun updateUser(user: UserEntity) {\n        viewModelScope.launch {\n            userRepository.updateUser(user)\n            \/\/ \u66f4\u65b0\u6210\u529f\u540e\uff0c\u53ef\u4ee5\u5728\u6b64\u5904\u89e6\u53d1LiveData\u6216Flow\u7b49\u901a\u77e5UI\u66f4\u65b0\n        }\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u7b2c<strong>\u4e03\uff1a\u5728Activity\/Fragment\/Compose\u4e2d\u4f7f\u7528ViewModel<\/strong><\/h3>\n\n\n\n<p>\u5728\u4f7f\u7528Hilt\u7684Activity\u6216Fragment\u6216\u8005Compse\u4e2d\uff0c\u901a\u8fc7<code>by viewModels()<\/code>\u59d4\u6258\u5c5e\u6027\u83b7\u53d6\u6ce8\u5165\u7684<code>UserViewModel<\/code>\u5b9e\u4f8b\uff0c\u5e76\u8c03\u7528\u5176<code>updateUser<\/code>\u65b9\u6cd5\u6765\u66f4\u65b0Room\u4e2d\u7684\u6570\u636e\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class MainActivity : ComponentActivity() {\n\n    private val userViewModel: UserViewModel by viewModels()\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContent {\n            MaterialTheme {\n                Index(userViewModel)\n            }\n        }\n    }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Composable\nfun Index(userViewModel: UserViewModel) {\n    var username: String by remember { mutableStateOf(\"\") }\n    var email: String by remember { mutableStateOf(\"\") }\n\n    Column {\n        OutlinedTextField(value = username, onValueChange = {\n            username = it\n            userViewModel.updateUser(UserEntity(1, username, email))\n        })\n        OutlinedTextField(value = email, onValueChange = {\n            email = it\n            userViewModel.updateUser(UserEntity(1, username, email))\n        })\n    }\n}<\/pre>\n\n\n\n<p><strong>\u81f3\u6b64\uff0c\u60a8\u5df2\u7ecf\u5b8c\u6210\u4e86\u5728Android\u5e94\u7528\u4e2d\u4f7f\u7528Hilt\u4f9d\u8d56\u6ce8\u5165\u6765\u66f4\u65b0Room\u6570\u636e\u5e93\u4e2d\u6570\u636e\u7684\u6240\u6709\u6b65\u9aa4\u3002\u5f53<code>updateUser<\/code>\u65b9\u6cd5\u5728ViewModel\u4e2d\u88ab\u8c03\u7528\u65f6\uff0cHilt\u4f1a\u786e\u4fdd\u6240\u6709\u4f9d\u8d56\uff08\u5982<code>UserRepository<\/code>\u548c<code>UserDao<\/code>\uff09\u5df2\u6b63\u786e\u6ce8\u5165\uff0c\u5e76\u901a\u8fc7\u5b83\u4eec\u4e0eRoom\u6570\u636e\u5e93\u8fdb\u884c\u4ea4\u4e92\u3002<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6dfb\u52a0\u4f9d\u8d56\uff1a \u4f7f\u7528Room\u7684\u4e09\u4e2a\u6b65\u9aa4\uff1a \u7b2c\u4e00\uff0c\u5b9a\u4e49\u6570\u636e\u5e93\uff08AppDatabase\u662f\u81ea\u5b9a\u4e49\u7684\u6570\u636e\u5e93\u7c7b\u540d\u79f0\uff09 \u5b9a\u4e49\u4e00 &hellip; <a href=\"https:\/\/blog.jishuge.cn\/?p=209\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">Android Jetpack Room\u4f7f\u7528\u7684\u5c0f\u7ed3\u3002<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":159,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,23],"tags":[],"class_list":["post-209","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-kotlin"],"_links":{"self":[{"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/posts\/209","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=209"}],"version-history":[{"count":7,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/posts\/209\/revisions"}],"predecessor-version":[{"id":222,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/posts\/209\/revisions\/222"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=\/wp\/v2\/media\/159"}],"wp:attachment":[{"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jishuge.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}