Jetpack 之 ViewModel 小白入手

声明 : https://www.jianshu.com/p/714062a9af75

简介:

  为了能更好的划分职能,Android 为我们提供了 ViewModel 类,专门用于存放应用程序页面所需要的数据.ViewModel 是将页面所需要的数据从页面中剥离出来,页面只需要处理用户交互和展示数据.
  ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在.

生命周期:

来自官网:


image.png

   屏幕旋转锁导致 Activity 重建,并不会影响 ViewModel 的声明周期

原理:

   看原理之前呢,先看看下面的使用方法哈~~~
   在页面中通过 ViewModelProvider 来实例化一个 ViewModel. ViewModelProvider 接受一个ViewModelStoreOwner类型的对象作为参数,我们实例化的是传的 this,代指当前的 Activity,这是因为我们的 Activity 集成自 ComponentActivity,而ComponentActivity默认实现了ViewModelStoreOwner接口.

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

       ........

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
}

   接口里面的方法返回的类型为ViewModelStore,从下面ViewModelStore的源码中可以看出来,ViewModel是以 HashMap 的形式被缓存了起来.ViewModel和界面之间没有直接的链接.他们通过ViewModelProvider进行关联,当页面需要 ViewModel 时,会向ViewModelProvider索要, ViewModelProvider会去 HashMap中查找,如果存在,直接返回,不存在,会实例化一个.

public class ViewModelStore {

    private final HashMap mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

     //........
}

⚠️⚠️⚠️敲黑板⚠️⚠️⚠️
   我们在使用ViewModel的时候,要特别注意.Activity由于配置变化导致的销毁重建不会影响ViewModel,ViewModel是独立于页面的,所以不要向ViewModel中传入任何类型的 Context 或者带有 Context 的引用对象,避免内存泄漏
  除了 Activity 实现了ViewModelStoreOwner接口外,Fragment 也实现了,,也可以正常使用 ViewModel.

使用方法

1,build.gradle 文件
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
2,创建 ViewModel 的类
class TestModel : ViewModel() {
    var number = 0
    
    //Activty 销毁时,才会被调用
    override fun onCleared() {
        super.onCleared()
    }
}

   ViewModel 是一个抽象类,其中有一个方法 onCleared().当 与 ViewModel 相关的Activity被销毁时,该方法才会被调用.我们可以在这个方法里面执行一些资源释放的相关操作,比如,取消倒计时之类的.但是,由于屏幕旋转二]而导致Activity重新创建,并不会调用这个方法.

3,在TestActivity中使用
class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        var testModel = ViewModelProvider(this).get(TestModel::class.java)
        textView1.text = testModel.number.toString()
        button_send.setOnClickListener(View.OnClickListener {
            testModel.number = testModel.number + 1
            textView1.text = testModel.number.toString()
        })
    }
}

   通过ViewModelProvider 实例化 ViewModel,ViewModelProvider会判断是否存在,若存在,会直接返回,若不存在,则会创建一个 ViewModel.
好了,看图:

图有点将就了

ViewModel 和 AndroidViewModel

   ViewModel 不能将任何类型的 Context 或者含有 Context 引用的对象传入 ViewModel,因为会引起内存泄漏,但是AndroidViewModel可以,它集成自 ViewModel,并接收 Applicatoin 作为 Context.它的生命周期是和 Application 一样的,所以不算内存泄漏.

ViewModel 和 onSaveInstanceState()

  one: onSaveInstanceState()只能保存少量的,支持序列化的数据,但是 ViewModel 没有这个限制.ViewModel 能保存页面中所有的数据,
  two: ViewModel不支持数据的持久化,当界面被彻底销毁时,ViewModel 中的数据就不存在了,但是onSaveInstanceState支持数据的持久化.
  二者,各有千秋.

END

image.png

你可能感兴趣的:(Jetpack 之 ViewModel 小白入手)