Android源码解析-ViewModel

前言

最近一个月主要实现了IM功能,其中UI框架使用了ViewModel和LiveData的存储和通知机制,实现后代码简洁易于维护。
感慨于Android arch components控件强大同时,须要顺带分析一波其中源码实现。今天先来分析一下ViewModel的源码实现。java

ViewModel简介

ViewModel是经过关联生命周期的方式来存储和管理跟UI相关的数据。即便configuration发生变化,在ViewModel中存放的数据是不会被销毁的。
没使用ViewModel的时候,若是系统Configuration发生变化,咱们的Activity会被销毁重建,致使Activity中的UI数据丢失。为了规避这个问题,咱们只能在onSaveInstanceState()将UI数据进行保存,在onCreate方法中判断savedInstanceState中是否有咱们存储的数据。
有了ViewModel以后,咱们只须要将数据存储到ViewModel便可,ViewModel中的数据不会随着Activity的销毁重建而消失。同时,若是不一样的Fragment使用相同的Activity对象来获取ViewModel,能够轻易的实现数据共享和通讯。app

使用ViewModel的例子:框架

// 自定义一个ViewModel,存储一个字符串
public class TestViewModel extends ViewModel {
    public String content;
    
    @Override
    protected void onCleared() {
        // 数据清理工做
        content = null;
    }
}

// 在Activity中获取并使用ViewModel
TestViewModel viewModel = ViewModelProviders.of(activity).get(TestViewModel.class);
Log.d("tag", viewModel.content);

三个问题

  1. ViewModel是如何建立出来的?
  2. 为何不一样的Fragment使用相同的Activity对象来获取ViewModel,能够轻易的实现ViewModel共享?
  3. ViewModel为何在Activity销毁重建时不会被销毁回收?

我我的习惯,看源码时候老是要带着问题去分析理解,这样才会有所收获。ide

源码分析

ViewModel是如何建立出来的?

经过示例代码,去掉链式调用后,咱们能够看到ViewModel是经过以下两步建立出来的:函数

// 1. 建立ViewModelProvider
ViewModelProvider viewModelProvider = ViewModelProviders.of(activity);

// 2. 经过反射获取ViewModel
TestViewModel viewModel = viewModelProvider.get(TestViewModel.class);

建立ViewModelProvider

先看下第一步的源码实现:源码分析

public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
    if (factory == null) {
        // 若是传入的对象建立工厂类为null,则使用默认的AndroidViewModelFactory来建立对象
        factory = AndroidViewModelFactory.getInstance(application);
    }
    
    // 建立一个ViewModelProvider
    return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory);
}

源码中,咱们发现建立一个ViewModelProvider须要传入两个参数:ViewModelStore和Factory。咱们先看下Factory的实现。学习

Factory

Factory顾名思义,定义了建立ViewModel的行为接口。里面只有一个create方法,用于子类自行决定如何实现一个ViewModel对象的建立。this

public interface Factory {
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

同时,ViewModelProvider源码内部也提供了两个默认Factory实现:NewInstanceFactory和AndroidViewModelFactory。google

// 直接反射Class对象的无参构造函数来建立ViewModel
public static class NewInstanceFactory implements Factory {
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        try {
            return modelClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        }
    }
}

// 1. 若是对象继承自AndroidViewModel,发射调用带Application参数的构造函数建立ViewModel对象;
// 2. 若是对象不继承自AndroidViewModel,则直接调用父类,即调用Class的无参构造函数建立ViewModel对象。
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    private static AndroidViewModelFactory sInstance;
    @NonNull
    public static AndroidViewModelFactory getInstance(@NonNull Application application) {
        if (sInstance == null) {
            sInstance = new AndroidViewModelFactory(application);
        }
        return sInstance;
    }

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

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            //noinspection TryWithIdenticalCatches
            try {
                return modelClass.getConstructor(Application.class).newInstance(mApplication);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
        return super.create(modelClass);
    }
}

启示:咱们自定义的ViewModel对象若是构造函数中须要其余各类参数,咱们只须要建立一个自定义的Factory类,而后调用该class的有参构造函数进行建立便可。spa

ViewModelStore

ViewModelStore就是个HashMap,经过key来获取ViewModel对象。

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

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

    final ViewModel get(String key) {
        return mMap.get(key);
    }
}

ViewModelProvider

了解了Factory实现和ViewModelStore实现后,咱们来看一下ViewModelProvider的get方法是如何建立ViewModel对象的。

public class ViewModelProvider {
    private final Factory mFactory;
    private final ViewModelStore mViewModelStore;

    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }

    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }    

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            return (T) viewModel;
        }
        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
}

ViewModleProvider的get方法实现也比较简单,总结一下就是:

  1. 使用ViewModel Class的canonicalName做为ViewModel在ViewModelStore中的惟一标识。
  2. 经过惟一标识,先查询一下ViewModelStore中是否有该ViewModel对象,若是有则直接返回。
  3. 若是ViewModelStore中没有该ViewModel对象,则经过Factory工厂类反射建立出ViewModel对象,存入ViewModelStore中,并返回给调用者。

小结

至此,第一个问题ViewModel是如何建立出来的已经分析完毕。接下来,咱们看第二个问题。

为何不一样的Fragment使用相同的Activity对象来获取ViewModel,能够轻易的实现ViewModel共享?

讲道理,若是同窗们仔细看了ViewModel的建立流程,这个问题天然迎刃而解。
由于不一样的Fragment使用相同的Activity对象来获取ViewModel,在建立ViewModel以前都会先从Activity提供的ViewModelStore中先查询一遍是否已经存在该ViewModel对象。因此咱们只须要先在Activity中一样调用一遍ViewModel的获取代码,便可让ViewModel存在于ViewModelStore中,从而不一样的Fragment能够共享一份ViewModel了。

ViewModel为何在Activity销毁重建时不会被销毁回收?

在看这个问题以前,咱们回到ViewModelProviders.of()源码中:

public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) {
    if (factory == null) {
        // 若是传入的对象建立工厂类为null,则使用默认的AndroidViewModelFactory来建立对象
        factory = AndroidViewModelFactory.getInstance(application);
    }
    
    // 建立一个ViewModelProvider
    return new ViewModelProvider(ViewModelStores.of(activity), (Factory)factory);
}

ViewModelProvider获取ViewModelStore是经过ViewModelStores.of(activity)实现的。咱们先看一下这个ViewModelStores作了什么操做。

ViewModelStores

看名字又像是一个封装好的工厂类。看下源码:

public static ViewModelStore of(@NonNull FragmentActivity activity) {
    return activity instanceof ViewModelStoreOwner ? ((ViewModelStoreOwner)activity).getViewModelStore() : HolderFragment.holderFragmentFor(activity).getViewModelStore();
}

经过源码能够发现,若是Activity是ViewModelStoreOwner的实现类,则直接经过activity获取ViewModelStore,若是不是,则经过HolderFragment.holderFragmentFor(activity).getViewModelStore()来获取。

经过查看FragmentActivity源码,发现其已是实现了ViewModelStoreOwner接口。

public class FragmentActivity extends BaseFragmentActivityApi16 implements
        ViewModelStoreOwner,
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {
}

因此这里咱们已经不须要理会HolderFragment了,不少分析ViewModel源码的文章都会花不少篇幅分析HolderFragment,我实在是搞不懂为何要这种操做。(初步怀疑是互相抄袭。。.)

虽然FragmentActivity实现了ViewModelStoreOwner接口,可以提供ViewModelStore,可是ViewModelStore是如何跟Activity生命周期关联起来的呢?

FragmentActivity中ViewModelStore的生命周期处理

搜索了一下FragmentActivity中关于ViewModelStore的调用,发现这里的实现应该跟生命周期处理有关。
FragmentActivity
google搜索了一下Activity的onRetainNonConfigurationInstance的做用:大部分同窗知道Activity由于configuration变化销毁和重建时会调用onSaveInstanceState和onRestoreInstanceState。与此同时,Activity其实还会回调onRetainNonConfigurationInstance和getLastNonConfigurationInstance方法。

onRetainNonConfigurationInstance和onSaveInstanceState做用相同,用来保存UI相关变量,当Activity意外销毁时,Activity的ViewModelStore对象就是在这里进行了保存。

那什么时机进行的恢复呢?
当Activity的onCreate调用时,会调用getLastNonConfigurationInstance,获取以前保存的ViewModelStore,若是ViewModelStore不为空,就进行赋值。这里进行了ViewModelStore的恢复。
Activity恢复

小结

这里咱们又学到了Activity的两个跟生命周期相关的函数调用:onRetainNonConfigurationInstance和getLastNonConfigurationInstance。

  1. Activity实现了ViewModelStoreOwner接口,建立了ViewModelStore对象。
  2. 当Activity意外销毁时,onRetainNonConfigurationInstance函数被回调,在此函数中对ViewModelStore对象进行了保存。
  3. 当Activity重建时,onCreate方法中会先获取getLastNonConfigurationInstance,若是其中的ViewModelStore对象不为空,就直接引用,再也不从新建立ViewModelStore对象了。

总结

三个问题分析完毕,相信你们已经对ViewModel的实现原理比较熟悉了。建议你们之后学习源码时,也带着问题去分析思考,事半功倍。

相关文章
相关标签/搜索