你真的了解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

less 复制代码
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来保存和管理数据:

kotlin 复制代码
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关联,以便在应用重新创建时检索。

kotlin 复制代码
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线程。

kotlin 复制代码
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的构造函数。

kotlin 复制代码
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: 每日一算法,由浅入深,欢迎加入一起共勉。

相关推荐
还鮟10 分钟前
CTF Web的数组巧用
android
伍哥的传说1 小时前
鸿蒙系统(HarmonyOS)应用开发之手势锁屏密码锁(PatternLock)
前端·华为·前端框架·harmonyos·鸿蒙
yugi9878381 小时前
前端跨域问题解决Access to XMLHttpRequest at xxx from has been blocked by CORS policy
前端
小蜜蜂嗡嗡1 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi002 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
浪裡遊2 小时前
Sass详解:功能特性、常用方法与最佳实践
开发语言·前端·javascript·css·vue.js·rust·sass
旧曲重听12 小时前
最快实现的前端灰度方案
前端·程序人生·状态模式
默默coding的程序猿3 小时前
3.前端和后端参数不一致,后端接不到数据的解决方案
java·前端·spring·ssm·springboot·idea·springcloud
夏梦春蝉3 小时前
ES6从入门到精通:常用知识点
前端·javascript·es6
归于尽3 小时前
useEffect玩转React Hooks生命周期
前端·react.js