Android-Jetpack

Jetpack系列组件--ViewModel从相遇到相知

2020-02-09  本文已影响0人  蓅哖伊人为谁笑
一、什么是ViewModel

不要将太多的逻辑处理、数据获取、存储放到 ViewModel 类,它仅仅作为 UI 数据的保存(暴露获取数据的方法),数据存储和获取可以创建 Repository 类(页面数据不复杂的情况,直接在ViewModel中读写也是可以的,灵活应用嘛)

二、 ViewModel的优势
三、如何引入ViewModel
  //包含了 viewmodel 和 livedata
  api 'androidx.lifecycle:lifecycle-extensions:2.1.0'

  //或者指明使用viewmodel
  api "androidx.lifecycle:lifecycle-viewmodel:2.1.0"

四、ViewModel如何使用

ViewModel的使用非常简单,这行代码便可以得到ViewModel对象。可以看到,允许传入ActivityFragment对象。所以对于单Activity,多Fragment的场景,我们可以利用这一特性,实现多Fragment页面之间的数据共享,页面通信。

MyViewModel viewModel = ViewModelProviders.of(Activity/Fragment).get(MyViewModel.class);
五、ViewModel数据存储,读取
六、ViewModel源码分析

ViewModel本身就是一个抽象类,没错,整个ViewModel的设计就是很简洁,我们需要到ViewModelProvider中继续分析

public abstract class ViewModel {
    
    protected void onCleared() {
    }
   ......省略其他无关紧要的代码
}

ViewModelProvider顾名思义,ViewModel提供者,它里面有一个对象ViewModelStore,用来存储当前页面一个个的ViewModel实例对象

ViewModelStore 内部就是一个HashMap。用以key-value存储ViewModel,非常简单。

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
        @Nullable Factory factory) {
    Application application = checkApplication(activity);
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    //在获取ViewModelProvider时要求传入ViewModelStore,此时就从Activity中获取了
   //还要求传入Factory,用以以何种方式创建ViewModel,默认是AndroidViewModelFactory。
   //该Factory允许ViewModel构造函数中携带一个Application参数。
   //对象的创建如下,如果创建失败,则调用空参构造函数创建ViewModel对象。
  //modelClass.getConstructor(Application.class).newInstance(mApplication);
    return new ViewModelProvider(activity.getViewModelStore(), factory);
}

关键点来了,想要ViewModel不随着宿主重建而销毁,那就要保证ViewModelStore不随着宿主重建而销毁。
那么ViewModelStore又是在什么时机被保存起来的呢?通过查看源码原来是利用ComponentActivity中的onRetainNonConfigurationInstancegetLastNonConfigurationInstance方法。
我们看一下ComponentActivity中的getViewModelStore方法:

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,如果不为空再获取viewModelStore
  //当配置发生改变可以重写onRetainCustomNonConfigurationInstance方法传入自定义数据,当需要时再通过getLastNonConfigurationInstance获取
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
          //如果没有获取到,创建ViewModelStore对象
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

再来看一下ComponentActivityonRetainNonConfigurationInstance如何保存viewModelStore

public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();
        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // 如果NonConfigurationInstance保存了viewModelStore,把它取出来
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom; 
        //把viewModelStore放到NonConfigurationInstances中并返回
        nci.viewModelStore = viewModelStore;
         //这样当页面被重建而销毁时ViewModelStore就被保存起来了。
        return nci;
    }

onRetainNonConfigurationInstance何时被调用,数据又是怎样保存的呢?了解过Activity启动流程的都知道ActivityThread,它控制着Activity的生命周期,当ActivityThread执行performDestroyActivity这个方法时,会调用Activity#retainNonConfigurationInstances获取到保存的数据并保存到ActivityClientRecord中。

ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason) {
        ...
           //保存retainNonConfigurationInstances中的数据到ActivityClientRecord中
         ActivityClientRecord r = mActivities.get(token);
         r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        ...
        return r;

当页面重建完成,ActivityThread执行了performLaunchActivity方法时,会调用Activityattach方法,便会把刚刚存储的数据,传递进去。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
       activity.attach(......, r.lastNonConfigurationInstances,.....);
}
七、ViewModel生命周期

由此可见,ViewModel的生命周期比宿主要长。但宿主被销毁时ViewModel的onCleared方法会被调用,在这里可以做清理释放的工作。


image.png
一起拥抱Jetpack
1.Jetpack全系列组件高级用法&原理分析实战
2.Jetpack系列组件--LiveData从相遇到相知
3.Jetpack系列组件--ViewModel从相遇到相知
4.Jetpack系列组件--优雅的打造一款事件总线LiveDataBus
5.Jetpack系列组件--列表分页库Paging从相遇到相知
6.Jetpack系列组件--Navigation组件工作原理分析&灵活改造应用
上一篇下一篇

猜你喜欢

热点阅读