jetpack-ViewModel

426 阅读4分钟

在2017年谷歌推出Android新的架构组件-一组可以帮助开发者设计强大的,可测试的和可维护的应用程序组件库。

下面我将重点介绍以下几个实用组件:

LifeCycle

LiveData

ViewModel

--------------------------------------------------------------------

ViewModel

官网地址

处理状态

1、ViewModel是什么

ViewModel,从字面上理解的话,我们也能想到它肯定是跟视图(View)以及数据(Model)相关的。正像它字面意思一样,它是负责准备和管理和UI组件(Fragment/Activity)相关的数据类,也就是说ViewModel是用来管理UI相关的数据的。同时ViewModel还可以用来负责UI组件间的通信,这一点后面我们会有例子说明。

2、ViewModel能够做什么

  • 保存(获取)数据
当Activity因为配置更改重新创建时,Activity必须重新获取数据。对于简单的数据,Activity可以使用 onSaveInstanceState()方法并从数据包中恢复其数据 ,但是此方法仅适用于可以序列化然后反序列化的少量数据,而不适用于潜在的大量数据,如用户列表或位图,而由于ViewModel贯穿了Activity的整个生命周期,且recreate时仍然存在,则可以用于保存/获取数据
  • 异步获取数据
UI控制器经常需要进行异步调用,这可能需要一些时间才能返回。UI控制器需要管理这些调用,并确保系统在销毁后清理它们以避免潜在的内存泄漏或崩溃。而通过ViewModel,可以拥有跟随Activity或Fragment的生命周期,无需关心内存泄漏和崩溃。
  • UI组件(Fragment)之间的通信

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}


public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, item -> {
           // Update the UI.
        });
    }
}

3、ViewModel的基本使用

在LiveData中已经使用了ViewModel,大家不记得的可以回头去看 LiveData

4、ViewModel生命周期

先来看下官网的一张图



上图是用Activity作为例子,左侧表示Activity的生命周期状态,右侧绿色部分表示ViewModel的生命周期范围。当屏幕旋转的时候,Activity会被recreate,Activity会经过几个生命周期方法,但是这个时候ViewModel还是之前的对象,并没有被重新创建,只有当Activity的finish()方法被调用时,ViewModel.onCleared()方法会被调用,对象才会被销毁。这张图很好的描述了是当Activity被recreate时,ViewModel的生命周期。

  另外,有个注意的地方:在ViewModel中不要持有Activity的引用。为什么要注意这一点呢?从上面的图我们看到,当Activity被recreate时,ViewModel对象并没有被销毁,如果Model持有Activity的引用时就可能会导致内存泄漏。那如果你要使用到Context对象怎么办呢,那就使用ViewModel的子类AndroidViewModel吧。

5、实现原理

类图


  • ViewModelProviders是ViewModel工具类,该类提供了通过Fragment和Activity得到ViewModel的方法,而具体实现又是有ViewModelProvider实现的。ViewModelProvider是实现ViewModel创建、获取的工具类。在ViewModelProvider中定义了一个创建ViewModel的接口类——Factory。ViewModelProvider中有个ViewModelStore对象,用于存储ViewModel对象。

  • ViewModelStore是存储ViewModel的类,具体实现是通过HashMap来保存ViewModle对象。

  • ViewModel是个抽象类,里面只定义了一个onCleared()方法,该方法在ViewModel不在被使用时调用。ViewModel有一个子类AndroidViewModel,这个类是便于要在ViewModel中使用Context对象,因为我们前面提到是不能在ViewModel中持有Activity的引用。

  • ViewModelStores是ViewModelStore的工厂方法类,它会关联HolderFragment,HolderFragment有个嵌套类——HolderFragmentManager。

时序图

在使用ViewModel的例子中,也许你会察觉得到一个ViewModel对象需要的步骤有点多啊,怎么不直接new一个出来呢?在你看到ViewModel的类图关系后,你应该就能明白了,因为是会缓存ViewModel对象的。下面以在Fragment中得到ViewModel对象为例看下整个过程的时序图。


时序图看起来比较复杂,但是它只描述了两个过程:

  • 得到ViewModel对象。
  • HolderFragment被销毁时,ViewModel收到onCleared()通知。

大家也可以结合时序图分析一下源码!