(一)理论基础
LiveData
和 ViewModel
是 Android 架构组件中的重要部分,它们在构建响应式、生命周期感知的 Android 应用程序中发挥着关键作用。下面分别介绍它们的原理。
LiveData 原理
1. 概述
LiveData
是一种可观察的数据持有者类,它具有生命周期感知能力,这意味着它能遵循其他应用组件(如 Activity
、Fragment
)的生命周期。只有处于活跃状态(如 STARTED
或 RESUMED
)的观察者才能收到数据更新的通知。
2. 核心组成部分
LiveData
类:作为数据的持有者,它内部维护了一个数据对象和一个观察者列表。Observer
接口 :定义了一个onChanged(T t)
方法,当LiveData
中的数据发生变化时,会调用该方法通知观察者。LifecycleOwner
接口 :表示具有生命周期的对象,如Activity
和Fragment
都实现了该接口。LiveData
通过Lifecycle
来感知LifecycleOwner
的生命周期状态。
3. 工作原理
- 注册观察者 :当调用
LiveData.observe(LifecycleOwner owner, Observer<? super T> observer)
方法时,LiveData
会将LifecycleOwner
和Observer
包装成一个LifecycleBoundObserver
对象,并将其添加到观察者列表中。同时,LifecycleBoundObserver
会监听LifecycleOwner
的生命周期变化。
java
// Java 示例
LiveData<String> liveData = new MutableLiveData<>();
observe(lifecycleOwner, new Observer<String>() {
@Override
public void onChanged(String s) {
// 处理数据变化
}
});
- 生命周期感知 :
LifecycleBoundObserver
实现了LifecycleEventObserver
接口,当LifecycleOwner
的生命周期状态发生变化时,LifecycleBoundObserver
会收到相应的事件通知。如果LifecycleOwner
进入活跃状态(STARTED
或RESUMED
),LiveData
会将最新的数据发送给该观察者;如果LifecycleOwner
进入销毁状态(DESTROYED
),LiveData
会自动移除该观察者,以避免内存泄漏。 - 数据更新 :当调用
LiveData.setValue(T value)
或LiveData.postValue(T value)
方法更新数据时,LiveData
会检查所有观察者的生命周期状态,只有处于活跃状态的观察者才会收到onChanged
方法的调用。
ViewModel 原理
1. 概述
ViewModel
旨在存储和管理与 UI 相关的数据,并且在配置更改(如屏幕旋转)时保持数据的一致性。它的生命周期比 Activity
或 Fragment
更长,直到关联的 Activity
或 Fragment
被销毁(对于 Activity
是 onDestroy()
调用且不是由于配置更改;对于 Fragment
是 onDestroy()
调用)。
2. 核心组成部分
ViewModel
类 :开发者自定义的ViewModel
类需要继承自ViewModel
类,用于存储和管理与 UI 相关的数据。ViewModelProvider
类 :负责创建和管理ViewModel
实例。它使用ViewModelStore
来存储ViewModel
实例。ViewModelStore
类 :是一个简单的键值对存储结构,用于存储ViewModel
实例。每个Activity
和Fragment
都有一个对应的ViewModelStore
。
3. 工作原理
- 创建
ViewModel
实例 :当调用ViewModelProvider(owner).get(MyViewModel.class)
方法时,ViewModelProvider
会首先检查ViewModelStore
中是否已经存在指定类型的ViewModel
实例。如果存在,则直接返回该实例;如果不存在,则使用ViewModelProvider.Factory
创建一个新的ViewModel
实例,并将其存储在ViewModelStore
中。
java
// Java 示例
ViewModelProvider viewModelProvider = new ViewModelProvider(this);
MyViewModel viewModel = viewModelProvider.get(MyViewModel.class);
- 配置更改时数据保留 :当发生配置更改(如屏幕旋转)时,
Activity
或Fragment
会被销毁并重新创建,但ViewModelStore
会被保留。因此,重新创建的Activity
或Fragment
可以从ViewModelStore
中获取之前的ViewModel
实例,从而保持数据的一致性。 - 生命周期管理 :当
Activity
或Fragment
被销毁(不是由于配置更改)时,ViewModelStore
会调用clear()
方法,该方法会遍历所有存储的ViewModel
实例,并调用它们的onCleared()
方法,以便进行资源释放。
LiveData
是具有生命周期感知能力的数据持有者,通过监听 LifecycleOwner
状态更新活跃观察者,ViewModel
借助 ViewModelProvider
和 ViewModelStore
存储管理 UI 数据,在配置更改时保留数据并在关联组件非配置更改销毁时清理资源。
下一阶段
Room 是 Android 官方提供的一个 SQLite 对象映射库,用于在 Android 应用中简化数据库操作,WorkManager 是 Android 架构组件之一,用于在应用中调度和管理后台任务。
Room 工作原理
- 抽象层封装 :Room 提供了一个抽象层,将 SQLite 数据库的操作抽象成 Java 或 Kotlin 接口和注解。开发者可以通过定义实体类(
@Entity
)、数据访问对象(@Dao
)和数据库类(@Database
)来描述数据库结构和操作。 - 编译时处理:在编译时,Room 会根据开发者定义的注解生成相应的 SQLite 语句和实现代码。这样可以在编译时发现数据库操作中的错误,提高开发效率和代码的健壮性。
- 线程管理:Room 默认不允许在主线程中执行数据库操作,因为数据库操作通常是耗时的,可能会导致 UI 卡顿。因此,Room 会将数据库操作放在后台线程中执行。
定义实体类:
Kotlin
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String,
val age: Int
)
定义数据访问对象(DAO):
Kotlin
import androidx.room.Dao
import androidx.room.Insert
@Dao
interface UserDao {
@Insert
suspend fun insertUser(user: User)
}
定义数据库类:
Kotlin
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
WorkManager 工作原理
- 任务调度:WorkManager 会根据任务的约束条件(如网络连接、电池状态等)和设备的当前状态来决定何时执行任务。它会尽量在设备处于空闲状态时执行任务,以减少对用户体验的影响。
- 任务持久化:WorkManager 会将任务信息持久化到本地数据库中,即使应用被杀死或设备重启,任务信息也不会丢失。当设备满足任务的约束条件时,WorkManager 会重新调度任务执行。
- 生命周期管理:WorkManager 会自动处理任务的生命周期,包括任务的执行、重试和取消等操作。它会根据任务的状态(如运行中、已完成、失败等)更新任务信息。
创建 WorkManager 任务
Kotlin
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import kotlinx.coroutines.runBlocking
class InsertUserWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
val database = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"app-database"
).build()
val userDao = database.userDao()
val user = User(name = "John", age = 30)
runBlocking {
userDao.insertUser(user)
}
return Result.success()
}
}
调度 WorkManager 任务
Kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val workRequest = OneTimeWorkRequest.Builder(InsertUserWorker::class.java).build()
WorkManager.getInstance(this).enqueue(workRequest)
}
}
Room + WorkManager 协同工作原理
- 数据交互:WorkManager 可以在后台任务中执行 Room 数据库操作,如插入、查询、更新和删除数据。这样可以避免在主线程中执行耗时的数据库操作,提高应用的性能和响应速度。
- 任务调度:当应用需要在特定条件下执行数据库操作时,可以使用 WorkManager 来调度这些任务。例如,当设备连接到网络时,执行数据同步任务,将本地数据库中的数据上传到服务器。
- 数据一致性:由于 WorkManager 会保证任务的执行,即使应用在任务执行过程中被杀死或设备重启,任务也会在合适的时机继续执行。这样可以确保数据库操作的完整性和数据的一致性。
总结:
Room 作为 Android 的 SQLite 对象映射库,在编译时根据注解生成数据库操作代码并管理线程,WorkManager 依据任务约束和设备状态调度持久化的后台任务,二者结合时 WorkManager 可在后台任务里执行 Room 的数据库操作,保障数据一致性,实现时先添加依赖,再定义 Room 数据库,创建 WorkManager 任务,最后调度任务执行。
下一篇我将讲述面试中我被项目拷打到的点!!!
感谢观看!!!