微信公众平台 网站 对接,云南网站建设哪家权威,蓝天使网站建设推广,php网站微信登录怎么做Android Jetpack 体验-官方codelab
1. 实现功能
使用 Jetpack 架构组件 Room、ViewModel 和 LiveData 设计应用#xff1b;从sqlite获取、保存、删除数据#xff1b;sqlite数据预填充功能#xff1b;使用 RecyclerView 展示数据列表#xff1b;
2. 使用架构组件
架构组…Android Jetpack 体验-官方codelab
1. 实现功能
使用 Jetpack 架构组件 Room、ViewModel 和 LiveData 设计应用从sqlite获取、保存、删除数据sqlite数据预填充功能使用 RecyclerView 展示数据列表
2. 使用架构组件
架构组件及其协作方式 LiveData 是一种可观察的数据存储器每当数据发生变化时它都会通知观察者。 LiveData会根据负责监听变化的生命周期自动停止或恢复观察。ViewModel 充当存储库和UI之间的通信中心以及应用程序中其他部分的UI相关的数据的容器。activity和fragment负责将数据绘制到屏幕上ViewModel负责保存并处理界面所需的所有数据。Repository 管理数据源可以是网络或本地的。RoomDatabase 简化数据库工作它使用 DAO 向 SQLite 数据库发起请求。DAO 数据访问对象一般是接口或抽象类SQLite 设备存储空间实体使用 Room 用于描述数据库表的带注解的类。
RoomWordSample 架构概览 3. 创建应用配置依赖 环境 Android Studio Flamingo | 2022.2.1 Patch 1 Android Gradle Plugin Version: 8.0.1 Gradle Version: 8.0 JDK 17 compileSdk 33 minSdk 24 targetSdk 33 统一项目依赖版本实现
在 build.gradle(root)下定义版本号注意 buildscript 一定要在最上面
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {ext{appCompatVersion 1.6.1activityVersion 1.6.0roomVersion 2.5.0lifecycleVersion 2.5.1coroutines 1.6.4constraintLayoutVersion 2.1.4materialVersion 1.9.0// testingjunitVersion 4.13.2androidxJunitVersion 1.1.5espressoVersion 3.5.1}
}plugins {id com.android.application version 8.0.1 apply falseid com.android.library version 8.0.1 apply falseid org.jetbrains.kotlin.android version 1.8.20 apply false
}然后在 build.gradle(app)下添加依赖
dependencies {implementation androidx.appcompat:appcompat:${rootProject.appCompatVersion}// activity-ktx 提供了 Kotlin 对 Android Activity API 的扩展。// 这些扩展函数和属性使得在 Kotlin 中使用 Activity API 更加简洁和方便。implementation androidx.activity:activity-ktx:${rootProject.activityVersion}// Room componentsimplementation androidx.room:room-ktx:${rootProject.roomVersion}implementation androidx.room:room-runtime:${rootProject.roomVersion}annotationProcessor androidx.room:room-compiler:${rootProject.roomVersion}kapt androidx.room:room-compiler:${rootProject.roomVersion}testImplementation androidx.room:room-testing:${rootProject.roomVersion}// Lifecycle componentsimplementation androidx.lifecycle:lifecycle-viewmodel-ktx:${rootProject.lifecycleVersion}implementation androidx.lifecycle:lifecycle-livedata-ktx:${rootProject.lifecycleVersion}
// implementation androidx.lifecycle:lifecycle-common-java8:${rootProject.lifecycleVersion}// kotlin components// core-ktx 提供了 Kotlin 对 Android 核心库的扩展。// 这些扩展函数和属性使得在 Kotlin 中使用 Android 核心库更加简洁和方便。implementation androidx.core:core-ktx:1.8.0implementation org.jetbrains.kotlinx:kotlinx-coroutines-core:${rootProject.coroutines}implementation org.jetbrains.kotlinx:kotlinx-coroutines-android:${rootProject.coroutines}// uiimplementation com.google.android.material:material:${rootProject.materialVersion}implementation androidx.constraintlayout:constraintlayout:${rootProject.constraintLayoutVersion}// TestingtestImplementation junit:junit:${rootProject.junitVersion}androidTestImplementation androidx.test.ext:junit:${rootProject.androidxJunitVersion}androidTestImplementation androidx.test.espresso:espresso-core:${rootProject.espressoVersion}
}build.gradle(app) 添加 kotlin 注解处理器插件
plugins {id com.android.applicationid org.jetbrains.kotlin.androidid kotlin-kapt
}java 版本相关设置 在build.gradle(app) 配置解决 Execution failed for task :app:kaptGenerateStubsDebugKotlin 错误.
compileOptions {sourceCompatibility JavaVersion.VERSION_17targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {jvmTarget 17
}AndroidX 版本查询 https://developer.android.google.cn/jetpack/androidx/versions?hlzh-cn
4. 创建实体
创建 Word 数据类描述在数据库中存储单词的表
package com.alex.roomwordssampleimport androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey/*** Author : alex* Date : on 2024/1/4 21:05.* Description :Word数据类用于定义数据库中的表*/
Entity(tableName word_table)
data class Word(PrimaryKey ColumnInfo(nameword) val word: String)该类描述 word_table 表只有一个列wordEntity(tableName word_table ) : 表名PrimaryKey: 主键ColumnInfo(name word ) 列名
5. 创建数据访问对象 DAO
DAO 定义 SQL 查询并将其与方法调用相关联。DAO 必须是一个接口或抽象类默认情况下所有查询必须在单独的线程上执行。 Room 支持 kotlin 协程可以使用 suspend 修饰符对查询进行注解然后从协程获取其他挂起函数对其进行调用。
WordDao 接口定义
package com.alex.roomwordssampleimport androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow/*** Author : alex* Date : on 2024/1/4 21:07.* Description :word 数据访问接口*/
Dao
interface WordDao {// 按照字母顺序获取所有单词// 为了观察数据变化情况返回值使用了Flow// 当数据库更新时它会发出一个新的流然后您可以使用该流更新UI。// 当Room查询返回LiveData或Flow时查询是在单独的线程上异步执行的。Query(SELECT * from word_table ORDER BY word ASC)fun getAlphabetizedWords(): FlowListWord// 插入单词// 将忽略与列表中的现有字词完全相同的新字词。Insert(onConflict OnConflictStrategy.IGNORE)suspend fun insert(word:Word)// 删除所有单词Query(DELETE FROM word_table)suspend fun deleteAll()
}解释
Dao 注解该接口表示为 Room 的 DAO类。删除使用的 Query可以定义复杂SQL语句。使用 kotlin-coroutines 中的 Flow定义返回数据类型是为了观察数据变化情况当数据发生变化时Room 会更新 Flow。
5. 添加 Room 数据库
Room 数据库类必须是抽象的必须扩展 RoomDatabase整个应用通常只需要一个 Room 数据库实例。 WordRoomDatabase 定义
package com.alex.roomwordssampleimport android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch/*** Author : alex* Date : on 2024/1/4 21:10.* Description : Room数据抽象类*/
Database(entities [Word::class], version 1, exportSchema false)
abstract class WordRoomDatabase: RoomDatabase(){abstract fun wordDao(): WordDaocompanion object{//单例,防止出现同时打开多个数据库实例的情况Volatileprivate var INSTANCE: WordRoomDatabase? nullfun getDatabase(context: Context,scope: CoroutineScope): WordRoomDatabase{return INSTANCE ?: synchronized(this){val instance Room.databaseBuilder(context.applicationContext,WordRoomDatabase::class.java,word_database).fallbackToDestructiveMigration().addCallback(WordDatabaseCallback(scope)).build()INSTANCE instanceinstance}}// 为了在数据库创建时填充它我们需要实现 RoomDatabase.Callback()并覆盖 onCreate()。private class WordDatabaseCallback(private val scope: CoroutineScope): RoomDatabase.Callback(){override fun onCreate(db: SupportSQLiteDatabase) {super.onCreate(db)INSTANCE?.let { database -scope.launch(Dispatchers.IO) {populateDatabase(database.wordDao())}}}}suspend fun populateDatabase(wordDao: WordDao){wordDao.deleteAll()var wordWord(Hello)wordDao.insert(word)wordWord(World)wordDao.insert(word)}}
}代码解释
Room 数据库类必须是抽象的必须扩展 RoomDatabase。Database 将该类注解为 Room 数据库并使用注解参数声明数据库中的实体以及设置版本号。数据库通过每个 Dao 的抽象getter方法公开 DAO定义单例 WordRoomDatabase防止同时打开数据库的多个实例。getDatabase 会返回单例首次使用时会创建数据库并删除旧数据填充示例数据。
6. 创建存储库
Repository 会将多个数据源的访问权限抽象化提供一个整洁的 API用于获取对应用其余部分的数据访问权限。 WordRepository 定义
package com.alex.roomwordssampleimport androidx.annotation.WorkerThread
import kotlinx.coroutines.flow.Flow/*** Author : alex* Date : on 2024/1/4 21:13.* Description : word 存储库可以用于管理多个数据源*/
class WordRepository(private val wordDao:WordDao) {// Room在单独的线程上执行所有查询// 观察数据变化情况返回值使用了Flowval allWords:FlowListWord wordDao.getAlphabetizedWords()// 在后台线程中执行操作Suppress(RedundantSuspendModifier)WorkerThreadsuspend fun insert(word: Word){wordDao.insert(word)}
}DAO 会被传递到存储库构造函数中而非整个数据库中。DAO 包含数据库的所有读取/写入方法因此它只需要访问 DAO无需向存储库公开整个数据库。allWords 表具有公开属性。它通过从 Room 获取 Flow 字词列表来进行初始化您之所以能够实现该操作是因为您在“观察数据库变化”步骤中定义 getAlphabetizedWords 方法以返回 Flow 的方式。Room 将在单独的线程上执行所有查询。Room 在主线程之外执行挂起查询。
7. 创建 ViewModel
ViewModel: 向界面提供数据不受配置变化的影响。ViewModel 是 Lifecycle 库的一部分。
LiveData与ViewModel的关系
LiveData 是一种可观察的数据存储器每当数据发生变化时您都会收到通知。与 Flow 不同LiveData 具有生命周期感知能力即遵循其他应用组件如 activity 或 fragment的生命周期。LiveData 会根据负责监听变化的组件的生命周期自动停止或恢复观察。因此LiveData 适用于界面使用或显示的可变数据。
ViewModel 会将存储库中的数据从 Flow 转换为 LiveData并将字词列表作为 LiveData 传递给界面。这样可以确保每次数据库中的数据发生变化时界面都会自动更新。
viewModelScope
AndroidX lifecycle-viewmodel-ktx 库将 viewModelScope 添加为 ViewModel 类的扩展函数。 WordViewModel 定义
package com.alex.roomwordssampleimport androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch/*** Author : alex* Date : on 2024/1/4 21:15.* Description : ViewModel 充当存储库和UI之间的通信中心以及应用程序中其他部分的UI相关的数据的容器。* ViewModel通过使用LiveData或Flow来保留数据这样它就可以在配置更改后继续存在。* ViewModel可以通过调用ViewModelProvider.Factory来创建。* activity和fragment负责将数据绘制到屏幕上ViewModel负责保存并处理界面所需的所有数据。*/
class WordViewModel(private val repository:WordRepository) :ViewModel(){// LiveData 是一种可观察的数据存储器每当数据发生变化时它都会通知观察者。// LiveData会根据负责监听变化的生命周期自动停止或恢复观察。// 使用 LiveData 并缓存 allWords 返回的内容有几个好处// - 我们可以在数据上设置一个观察者而不是轮询变化并且只有当数据实际发生变化时才更新用户界面。// - 通过 ViewModel仓库与用户界面完全分离。val allWords: LiveDataListWord repository.allWords.asLiveData()// 启动一个新的协程以非阻塞方式插入数据。fun insert(word: Word) viewModelScope.launch {repository.insert(word)}
}/*** WordViewModelFactory 类的作用是创建 WordViewModel 实例* 并确保 WordViewModel 可以接收到 WordRepository 实例以便它可以与数据源进行交互。*/
class WordViewModelFactory(private val repository: WordRepository): ViewModelProvider.Factory{override fun T : ViewModel create(modelClass: ClassT): T {// 检查modelClass是否是WordViewModel的子类if (modelClass.isAssignableFrom(WordViewModel::class.java)){Suppress(UNCHECKED_CAST)return WordViewModel(repository) as T}throw IllegalArgumentException(Unknown ViewModel class)}
}解析
创建了一个名为 WordViewModel 的类该类可获取 WordRepository 作为参数并扩展 ViewModel。存储库是 ViewModel 需要的唯一依赖项。如果需要其他类系统也会在构造函数中传递相应的类。添加了一个公开的 LiveData 成员变量以缓存字词列表。使用存储库中的 allWords Flow 初始化了 LiveData。然后您通过调用 asLiveData(). 将该 Flow 转换成了 LiveData。创建了一个可调用存储库的 insert() 方法的封装容器 insert() 方法。这样一来便可从界面封装 insert() 的实现。我们将启动新协程并调用存储库的挂起函数 insert。如上所述ViewModel 的协程作用域基于它的名为 viewModelScope 的生命周期您将在这里使用。创建了 ViewModel并实现了 ViewModelProvider.Factory后者可获取创建 WordViewModel 所需的依赖项作为参数WordRepository。
使用 viewModels 和 ViewModelProvider.Factory 后框架将负责 ViewModel 的生命周期。它不受配置变化的影响即使重建 activity您始终能得到 WordViewModel 类的正确实例。
使用asLiveData需要添加下面的依赖 添加依赖implementation androidx.lifecycle:lifecycle-livedata-ktx:2.3.1引入import androidx.lifecycle.asLiveData8. 列表页面布局实现MainActivity
列表页面使用了 RecyclerView 组件需要先定义列表项布局 recyclerview_item.xml
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentTextViewandroid:idid/textViewstylestyle/word_titleandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:backgroundandroid:color/holo_orange_light //LinearLayout在activity_main.xml 中引入 RecyclerView并添加一个浮动按钮
?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parenttools:context.MainActivityandroidx.recyclerview.widget.RecyclerViewandroid:idid/recyclerviewandroid:layout_width0dpandroid:layout_height0dptools:listitemlayout/recyclerview_itemandroid:paddingdimen/big_paddingapp:layout_constraintBottom_toBottomOfparentapp:layout_constraintLeft_toLeftOfparentapp:layout_constraintRight_toRightOfparentapp:layout_constraintTop_toTopOfparent/com.google.android.material.floatingactionbutton.FloatingActionButtonandroid:idid/fabapp:layout_constraintBottom_toBottomOfparentapp:layout_constraintEnd_toEndOfparentandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_margin16dpandroid:contentDescriptionstring/add_wordandroid:srcdrawable/id_add_black_24db//androidx.constraintlayout.widget.ConstraintLayout浮动按钮图标的制作使用了 Asset Studio 工具File-New-Vector Asset
9. RecyclerView
MainActivity 中 使用 RecyclerView 显示数据。 添加步骤
定义 WordListAdapter 类定义填充列表项行为在 MainActivity 中添加 RecyclerView
WordListAdapter 类定义
package com.alex.roomwordssampleimport android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView/*** Author : alex* Date : on 2024/1/4 21:40.* Description :RecyclerView的适配器*/
class WordListAdapter:ListAdapterWord, WordListAdapter.WordViewHolder(WordsComparator()) {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder {return WordViewHolder.create(parent)}override fun onBindViewHolder(holder: WordViewHolder, position: Int) {val currentgetItem(position)holder.bind(current.word)}class WordViewHolder(itemView:View):RecyclerView.ViewHolder(itemView) {private val wordItemView:TextView itemView.findViewById(R.id.textView)fun bind(text:String?){wordItemView.texttext}companion object{fun create(parent:ViewGroup):WordViewHolder{val view:ViewLayoutInflater.from(parent.context).inflate(R.layout.recyclerview_item,parent,false)return WordViewHolder(view)}}}class WordsComparator : DiffUtil.ItemCallbackWord() {override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {return oldItem newItem}override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {return oldItem.word newItem.word}}
}RecyclerView 是 Android 中用于显示大量数据集的一个组件它优化了这些数据的显示只创建和渲染屏幕上可见的部分从而提高了性能。
RecyclerView 通过一个适配器来管理数据的显示适配器负责将数据与每个列表项视图item view进行绑定。
RecyclerView.ViewHolder 是一个静态类用于存储对列表项视图中的界面元素的引用。
在这个例子中WordViewHolder 是 RecyclerView.ViewHolder 的一个子类它存储了对 TextView 的引用并提供了一个 bind 方法来更新 TextView 的内容。
class WordViewHolder(itemView:View):RecyclerView.ViewHolder(itemView) {private val wordItemView:TextView itemView.findViewById(R.id.textView)fun bind(text:String?){wordItemView.texttext}...
}ListAdapter 是 RecyclerView.Adapter 的一个子类它使用 DiffUtil 来计算数据集的最小更新。当数据发生变化时ListAdapter 会计算出新旧数据集之间的差异并使用这些差异来更新 RecyclerView。
在这个例子中WordListAdapter 是 ListAdapter 的一个子类它使用 WordsComparator 来计算数据集的差异。 WordsComparator 是 DiffUtil.ItemCallback 的一个子类它提供了两个方法areItemsTheSame 和 areContentsTheSame。
areItemsTheSame 用于检查两个 Word 是否表示同一个对象areContentsTheSame 用于检查两个 Word 的内容是否相同。
class WordsComparator : DiffUtil.ItemCallbackWord() {override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {return oldItem newItem}override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {return oldItem.word newItem.word}
}WordViewHolder 中的 create 静态方法用于创建 WordViewHolder 的实例。这个方法接收一个 ViewGroup 类型的参数 parent这通常是 RecyclerView。
在 create 方法中首先通过 LayoutInflater 从 recyclerview_item.xml 布局文件中创建一个新的视图。然后将这个新创建的视图作为参数传递给 WordViewHolder 的构造函数创建一个 WordViewHolder 的实例。
这样做的好处是WordViewHolder 的创建逻辑被封装在 WordViewHolder 类内部使得 WordListAdapter 的代码更加简洁。同时如果 WordViewHolder 的创建逻辑需要修改只需要在 WordViewHolder 类内部修改而不需要修改 WordListAdapter 的代码。
在MainActivity中添加 RecyclerView:
setContentView(R.layout.activity_main)val recyclerViewfindViewByIdRecyclerView(R.id.recyclerview)
val adapterWordListAdapter()
recyclerView.adapteradapter
recyclerView.layoutManager LinearLayoutManager(this)10. 在应用中实例化Repository和Database
您希望应用中的数据库和存储库只有一个实例。实现该目的的一种简单的方法是将它们作为 Application 类的成员进行创建。然后在需要时只需从应用检索而不是每次都进行构建。 创建 WordsApplication继承自 Application:
package com.alex.roomwordssampleimport android.app.Application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob/*** Author : alex* Date : on 2024/1/4 22:03.* Description : 实现Application类以便在整个应用程序中使用单个实例*/
class WordsApplication: Application(){// 为应用程序的生命周期创建一个作用域以便在应用程序被销毁时取消所有协程// 不需要取消这个作用域因为它会随着进程的结束而被销毁。// SupervisorJob() 创建了一个新的 Job 实例并将其作为参数传递给 CoroutineScope 的构造函数创建了一个新的协程作用域 applicationScope。// 这个作用域的特性是它的子协程之间是相互独立的一个子协程的失败不会导致其他子协程的取消。val applicationScope CoroutineScope(SupervisorJob())val database by lazy {WordRoomDatabase.getDatabase(this,applicationScope)}val repository by lazy { WordRepository(database.wordDao()) }
}在 AndroidManifest 文件将 WordApplication 设为 application android:name
11. 填充数据库
在 WordRoomDatabase 定义了 WordDatabaseCallback 用于在创建数据库的时候删除旧数据并添加示例数据
12. 添加 新增数据页面 NewWordActivity
布局 activity_new_word.xml:
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:orientationverticalandroid:layout_widthmatch_parentandroid:layout_heightmatch_parenttools:context.NewWordActivityEditTextandroid:idid/edit_wordandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:minHeightdimen/min_heightandroid:fontFamilysans-serif-lightandroid:hintstring/hint_wordandroid:inputTypetextAutoCompleteandroid:layout_margindimen/big_paddingandroid:textSize18sp /Buttonandroid:idid/button_saveandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:backgroundcolor/purple_500android:textstring/button_saveandroid:layout_margindimen/big_paddingandroid:textColorcolor/buttonLabel //LinearLayoutNewWordActivity 代码
package com.alex.roomwordssampleimport android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.widget.Button
import android.widget.EditTextclass NewWordActivity : AppCompatActivity() {private lateinit var editWordView:EditTextoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_new_word)editWordView findViewById(R.id.edit_word)val button findViewByIdButton(R.id.button_save)button.setOnClickListener {val replyIntent Intent()if(TextUtils.isEmpty(editWordView.text)){setResult(Activity.RESULT_CANCELED,replyIntent)}else{val word editWordView.text.toString()replyIntent.putExtra(EXTRA_REPLY,word)setResult(Activity.RESULT_OK,replyIntent)}finish()}}companion object{const val EXTRA_REPLY com.alex.roomwordssample.REPLY}
}13. 数据与页面关联
最后一步是将界面连接到数据库方法是保存用户输入的新字词并在 RecyclerView 中显示当前字词数据库的内容。
如需显示数据库的当前内容请添加可观察 ViewModel 中的 LiveData 的观察者。
每当数据发生变化时系统都会调用 onChanged() 回调此操作会调用适配器的 setWords() 方法来更新此适配器的缓存数据并刷新显示的列表。
1. 在 MainActivity 中创建 ViewModel
// 通过 viewModels 委托属性实现ViewModel的实例化
private val wordViewModel: WordViewModel by viewModels {WordViewModelFactory((application as WordsApplication).repository)
}这里使用了 viewModels 委托并传入了 WordViewModelFactory 实例该实例基于从 WordApplication 中检索的存储库构建而成。
当观察到数据发生变化且 activity 在前台显示时将触发 onChanged() 方法
// 通过调用 observe() 来观察 LiveData 对象传入 LifecycleOwner 和 Observer。
wordViewModel.allWords.observe(this){ words -words.let { adapter.submitList(it) }
}浮动按钮点击事件将打开 NewWordActivity 这里使用了registerForActivityResult 方法和 ActivityResultContracts因为 startActivityForResult 和 onActivityResult 方法在 Android 11API 30中已被弃用。
完整代码
package com.alex.roomwordssampleimport android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButtonimport androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.ActivityResultLauncher
class MainActivity : AppCompatActivity() {// 请求代码打开 NewWordActivity 时使用
// private val newWordActivityRequestCode 1private lateinit var newWordActivityLauncher: ActivityResultLauncherIntent// 通过 viewModels 委托属性实现ViewModel的实例化private val wordViewModel: WordViewModel by viewModels {WordViewModelFactory((application as WordsApplication).repository)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val recyclerViewfindViewByIdRecyclerView(R.id.recyclerview)val adapterWordListAdapter()recyclerView.adapteradapterrecyclerView.layoutManager LinearLayoutManager(this)// 通过调用 observe() 来观察 LiveData 对象传入 LifecycleOwner 和 Observer。wordViewModel.allWords.observe(this){ words -words.let { adapter.submitList(it) }}val fab findViewByIdFloatingActionButton(R.id.fab)newWordActivityLauncher registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -if (result.resultCode Activity.RESULT_OK) {val data: Intent? result.datadata?.getStringExtra(NewWordActivity.EXTRA_REPLY)?.let { reply -val word Word(reply)wordViewModel.insert(word)}} else {Toast.makeText(applicationContext,R.string.empty_not_saved,Toast.LENGTH_LONG).show()}}fab.setOnClickListener {val intent Intent(thisMainActivity, NewWordActivity::class.java)// startActivityForResult 和 onActivityResult 方法在 Android 11API 30中已被弃用。// 取而代之的是 registerForActivityResult 方法和 ActivityResultContracts 类。
// startActivityForResult(intent, newWordActivityRequestCode)newWordActivityLauncher.launch(intent)}}// override fun onActivityResult(requestCode: Int, resultCode: Int, intentData: Intent?) {
// super.onActivityResult(requestCode, resultCode, intentData)
//
// if (requestCode newWordActivityRequestCode resultCode Activity.RESULT_OK) {
// intentData?.getStringExtra(NewWordActivity.EXTRA_REPLY)?.let { reply -
// val word Word(reply)
// wordViewModel.insert(word)
// }
// } else {
// Toast.makeText(
// applicationContext,
// R.string.empty_not_saved,
// Toast.LENGTH_LONG
// ).show()
// }
// }}