盒子
盒子
文章目录
  1. 引言
  2. 什么是ViewModel?
  3. 原理解析
  4. 为什么需要ViewModelStore
  5. 简单示例
  6. 高级运用
    1. 使用SavedStateHandle
    2. 处理异步操作
    3. 使用Factory
  7. 注意事项和优化技巧
  8. 结语
  9. 推荐

你真的了解ViewModel的设计思想吗?

引言

Android开发中,数据的管理是一个至关重要的问题。随着应用复杂度的增加,我们需要一种能够有效管理数据和处理UI相关逻辑的机制。Android架构组件中的ViewModel应运而生。本文将深入探讨ViewModel的原理,并介绍其高级运用,旨在帮助开发者更好地理解和运用这一组件。

什么是ViewModel?

ViewModel是一种设计模式,它的目标是将UI控制器(Activity、Fragment等)与数据分离,同时保持UI的状态。在Android中,ViewModel通常用于存储和管理与UI相关的数据,以确保这些数据在屏幕旋转或配置更改等情况下不会丢失。

原理解析

ViewModel的原理是基于ViewModelStore类。ViewModelStore类是一个存储ViewModel的容器。当UI控制器创建时,系统会为其创建一个ViewModelStore实例。当 UI控制器销毁时,系统会销毁其对应的ViewModelStore实例。

ViewModel在创建时,会将自身注册到其所在的ViewModelStore实例中。当UI控制器销毁时,系统会从其对应的ViewModelStore实例中移除ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

open class ViewModelStore {

//存储viewmodel
private val map = mutableMapOf<String, ViewModel>()
...

}

// 自动创建
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
ensureViewModelStore();
getLifecycle().removeObserver(this);
}
});

// 销毁
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
mReportFullyDrawnExecutor.activityDestroyed();
}
}
});

所以ViewModelStore的创建与ViewModel的销毁,都与Lifecycle有关,这样就让ViewModel具有以下特性:

  1. 生命周期感知: ViewModel是生命周期感知的,它会自动跟踪UI控制器的生命周期,并在适当的时候进行清理。这意味着我们无需担心内存泄漏或不必要的资源占用。
  2. 持久性存储: ViewModel可以存储大量的数据,并且在配置更改时仍然保持活动。这是通过将ViewModel与UI控制器分离,将其保存在ViewModelStore中实现的。
  3. 数据共享: 多个UI控制器可以共享同一个ViewModel,这为不同组件之间的数据共享提供了便利。这对于在Activity和Fragment之间传递数据非常有用。

为什么需要ViewModelStore

ViewModelStore是用于管理ViewModel实例的生命周期的一种机制。它的存在是为了解决以下问题:

  1. 生命周期一致性:在Android开发中,我们经常遇到配置更改(如屏幕旋转)导致Activity或Fragment被销毁并重新创建的情况。这种情况下,我们希望保持与UI相关的数据的一致性,即使UI重新创建,数据也不会丢失。ViewModelStore通过管理ViewModel实例的生命周期,确保在重新创建UI时,旧的ViewModel实例被正确地销毁,而新的ViewModel实例被正确地创建。
  2. 资源管理:每个ViewModel实例可能持有一些资源,如数据库连接、网络连接等。如果这些资源没有被正确地释放,就会导致内存泄漏和资源浪费。ViewModelStore通过在适当的时机销毁ViewModel实例,确保这些资源可以被正确地释放,避免了内存泄漏和资源浪费。
  3. 数据共享:ViewModelStore允许多个组件共享同一个ViewModel实例。这在某些情况下非常有用,比如一个Activity和它的多个Fragment需要访问和更新相同的数据。通过使用ViewModelStore,这些组件可以共享同一个ViewModel实例,避免了数据的重复加载和同步问题。

简单示例

以下是一个简单的ViewModel示例,演示了如何使用ViewModel来保存和管理数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class MyViewModel : ViewModel() {
private val state = MutableLiveData<String>()

fun setData(value: String) {
sate.value = value
}

fun getData(): LiveData<String> {
return state
}
}

class MyActivity : AppCompatActivity() {

private val viewModel: MyViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// 观察 ViewModel 的数据变化
viewModel.getData().observe(this, { data ->
// 更新 UI
})
}
}

在上述代码中,ViewModel包含一个MutableLiveData来存储数据。通过setData和getData方法,我们可以设置和获取数据。这个ViewModel将在配置更改时保持活动,确保数据不会丢失。

高级运用

使用SavedStateHandle

SavedStateHandle是一个可用于在配置更改后保持数据的工具。它允许我们将数据与ViewModel关联,以便在应用重新创建时检索。

1
2
3
4
5
6
7
8
9
10
11
class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val dataKey = "data_key"

fun setData(value: String) {
savedStateHandle.set(dataKey, value)
}

fun getData(): String? {
return savedStateHandle.get(dataKey)
}
}

处理异步操作

ViewModel可以与协程结合,以处理异步操作。这使得在ViewModel中执行耗时操作成为可能,而不会阻塞UI线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyViewModel : ViewModel() {
private val data = MutableLiveData<String>()

fun fetchData() {
viewModelScope.launch {
// 执行耗时操作
val result = fetchDataFromRepository()
data.value = result
}
}

fun getData(): LiveData<String> {
return data
}
}

使用Factory

ViewModelProvider.Factory用于自定义ViewModel的创建过程,可以传递参数ViewModel的构造函数。

1
2
3
4
5
6
7
8
9
class MyViewModelFactory(private val repository: MyRepository) : ViewModelProvider.Factory {

override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
return MyViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

注意事项和优化技巧

  • 避免在ViewModel中持有View的引用,以防止内存泄漏。
  • ViewModel的职责限制在处理UI相关的逻辑,不要包含过多的业务逻辑。
  • 谨慎使用SavedStateHandle,避免将大量数据存储在其中导致性能问题。

结语

通过深入理解ViewModel的原理和高级运用,我们可以更好地利用这一强大的架构组件。ViewModel的设计模式和生命周期感知使其成为Android开发中不可或缺的一部分。希望本文能够帮助大家更好地应用和理解ViewModel

推荐

android_startup: 提供一种在应用启动时能够更加简单、高效的方式来初始化组件,优化启动速度。不仅支持Jetpack App Startup的全部功能,还提供额外的同步与异步等待、线程控制与多进程支持等功能。

AwesomeGithub: 基于Github的客户端,纯练习项目,支持组件化开发,支持账户密码与认证登陆。使用Kotlin语言进行开发,项目架构是基于JetPack\&DataBinding的MVVM;项目中使用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。

flutter_github: 基于Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。

android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。

daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。

支持一下
赞赏是一门艺术