Android ViewModel详解

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119828016
本文出自【赵彦军的博客】

ViewModel简介

视图与数据模型之间的桥梁ViewModel

ViewModel生命周期

在这里插入图片描述
ViewModel的生命周期会比创建它的Activity、Fragment的生命周期都要长。即ViewModel中的数据会一直存活在Activity/Fragment中。

众所周知,由于Android平台的特殊性,若应用程序发送屏幕旋转的时候会经历Activity的销毁与重建,这里就涉及到数据保存的问题。虽然Activity可以通过onSaveInstanceState()机制保存与恢复数据,但是onSaveInstanceState()方法只能存储少量的数据进行恢复,但是遇到大量的数据该怎么办呢?

幸运的是,ViewModel能完美的为我们解决这个问题,ViewModel有自己独立的生命周期,屏幕旋转所导致的Activity重建,并不会影响ViewModel的生命周期.

ViewModel 使用

implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'

写一个继承自ViewModel的类

class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData<List<User>>().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

使用:

class MainActivity : AppCompatActivity() {

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

        val mainViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        mainViewModel.getUsers()

        //或者引入 extensions
        //implementation "android.arch.lifecycle:extensions:1.1.1"
        val mainViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java);
    }

}

ViewModel是一个抽象类,其中只有一个onCleared()方法。当ViewModel不再被需要,即与之相关的Activity都被销毁时,该方法会被系统调用。我们可以在该方法中执行一些资源释放的相关操作。注意: 当屏幕旋转而导致的Activity重建,并不会调用该方法。

class MyViewModel : ViewModel() {

    override fun onCleared() {
        super.onCleared()
        //viewModel销毁时调用,可以做一些释放资源的操作
    }
}

我们可以在onCleared()对定时器资源的释放,防止造成内存泄露。

Fragment使用

class ItemFragment : Fragment() {

    var mainViewModel: MyViewModel? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val mainViewModel = ViewModelProvider(requireActivity()).get(MyViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_item_list, container, false)
        return view
    }
}

ktx 扩展

activity 扩展

在上面我们介绍了,在activity里获取 viewModel 实例的方法,如下:

val mainViewModel = ViewModelProvider(this).get(MyViewModel::class.java)

但是 Kotlin 的 ktx 扩展包里面有更为简洁的方式,添加依赖如下:

implementation "androidx.activity:activity-ktx:1.3.1"

使用如下:

class MainActivity : AppCompatActivity() {

    val mainViewModel by viewModels<MyViewModel>()

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

        mainViewModel.name = "hhhh"
    }
}

viewModels 扩展方法如下:

public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        defaultViewModelProviderFactory
    }

    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}

fragment 扩展

对于 fragment 我们以前是使用:

val mainViewModel = ViewModelProvider(requireActivity()).get(MyViewModel::class.java)

同理,我们添加 fragment ktx 扩展

implementation "androidx.fragment:fragment-ktx:1.3.6"

就可以使用 :

val mainViewModel: MyViewModel by activityViewModels()

具体代码如下

class ItemFragment : Fragment() {

    val mainViewModel: MyViewModel by activityViewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_item_list, container, false)
        return view
    }
}

AndroidViewModel

使用ViewModel的时候,需要注意的是ViewModel不能够持有View、Lifecycle、Acitivity引用,而且不能够包含任何包含前面内容的类。因为这样很有可能会造成内存泄漏。

普通的 ViewModel 生命周期都很短,随着activity 销毁而销毁。如果我们要创建一个长生命周期的 ViewModel 怎么办? 其实Android 已经给我们提供了一个 AndroidViewModel

下面是一个AndroidViewModel的源码:

public class AndroidViewModel extends ViewModel {
    @SuppressLint("StaticFieldLeak")
    private Application mApplication;

    public AndroidViewModel(@NonNull Application application) {
        mApplication = application;
    }

    /**
     * Return the application.
     */
    @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
    @NonNull
    public <T extends Application> T getApplication() {
        return (T) mApplication;
    }
}

可以看到 AndroidViewModel 持有了一个 Application ,所以它的生命周期会很长。

具体使用如下:

class MyViewModel(application: Application) : AndroidViewModel(application) {

    override fun onCleared() {
        super.onCleared()
        //viewModel销毁时调用,可以做一些释放资源的操作
    }

}

其实延伸开,我们完全可以在 AndroidViewModel 中存储一些全局数据。

ViewModel onCleared 原理解析

你有没有想过,当 ActivityFragment 销毁的时候,ViewModelonCleared 方法为什么会回调?

当你看到下面这两个图,你就明白了

Activity 中的 ViewModel 原理

ComponentActivity 注册 LifecycleEventObserver , 在 onDestory() 执行 getViewModelStore().clear();
在这里插入图片描述
ViewModelStore
在这里插入图片描述
上面就是 Activity 的原理。

Fragment 中的 ViewModel 原理

因为 Activity 销毁导致 Fragment 销毁

对于 Fragment 来说,要复杂一下:

FragmentActivity

在这里插入图片描述
FragmentController

在这里插入图片描述

FragmentStateManager

在这里插入图片描述

FragmentManagerViewModel

在这里插入图片描述

因为 Fragment 替换导致 Fragment 销毁

比如在 Activity 先执行 , add 方法

      supportFragmentManager.beginTransaction()
                .add(R.id.fragc, MyFragmentA(), "sdsds")
                .commitAllowingStateLoss()

再执行 replace 方法

    supportFragmentManager.beginTransaction()
            .replace(R.id.fragc, MyFragmentB(), "sdsds")
            .commitAllowingStateLoss()

执行完 replace MyFragmentB , 那么 MyFragmentA 就会被销毁。对应的 MyFragmentA 中的 ViewModel 就会执行 onCleared 方法。

原理如下:

FragmentStateManager

在这里插入图片描述

FragmentManagerViewModel

在这里插入图片描述

这种情况和上一种不一样 。

本次情况 Activity 没销毁,是因为 fragment 执行 replace 导致前 fragment 销毁。
而上一种情况是因为 Activity 销毁,导致 fragment 销毁。

  • 8
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Jetpack是Google提供的一套用于加速Android应用开发的工具包,其中包括了许多架构组件,其中之一就是ViewModelViewModel是一种设计模式,用于保存和管理与UI相关的数据。在传统的Android开发中,当屏幕旋转或者因为其他原因导致Activity或Fragment重建时,之前保存的临时数据就会丢失。而ViewModel的出现解决了这个问题。 ViewModel的主要作用是将数据与UI组件分离。它的工作方式是创建一个ViewModel类,并在其中保存需要与UI组件交互的数据。这样,当屏幕旋转或重建时,ViewModel实例不会销毁,数据也会得到保留。然后,在Activity或Fragment中,通过获取ViewModel实例,可以轻松地访问这些数据。 使用ViewModel的好处有很多。首先,它可以避免内存泄漏,因为ViewModel的生命周期与Activity或Fragment无关。其次,它可以节省资源,因为当Activity或Fragment销毁时,ViewModel实例可以被系统缓存起来,下次再创建时可以直接返回该实例。另外,由于ViewModel保存了与UI相关的数据,可以减少因为屏幕旋转导致的数据重复加载的问题。 在使用ViewModel时,你可以选择使用Android Jetpack中的其他架构组件来进一步提高开发效率,比如通过LiveData实现数据的观察和通知,或者通过DataBinding来实现UI与数据的自动绑定。 总之,ViewModelAndroid Jetpack中非常重要的一个架构组件,它的出现实现了数据与UI的解耦,提高了开发效率,并且解决了数据丢失的问题。希望通过这篇文档的详解,你对ViewModel有了更深入的理解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值