欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android architecture components学习笔记2-ViewModel源码分析

程序员文章站 2022-05-14 15:26:03
...

前言

在上一篇博客中,我们从总体上介绍了AAC架构组件,以及Lifecycle组件的使用和源码解析,现在我们来了解ViewModel组件的使用和源码。

ViewModel的作用

ViewModel是android架构组件中非常重要的一个组件,它是Android架构分层的核心,有关它的用法和资料可以可以参考官方给出的示例https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html

ViewModel的官方定义如下:ViewModel是存储和管理lifecycle 重新创建的数据的组件,在lifecycle 在配置改变或者屏幕旋转时数据仍然在生存周期内。另外ViewModel还可以用来负责UI组件间的通信,它是解耦Activity/Fragment View层的关键。

ViewModel在AAC架构组件中的位置如下:
Android architecture components学习笔记2-ViewModel源码分析

可以看到它位于Activity(View)和数据仓库(Model)层之间,类似于MVP中的P或者mvvm中的vm,那么问题就来了,大家都知道,我们平时使用mvp或者mvvm的过程中,Present或者ViewModel类都是我们自己定义的,并不需要继承自某个类,google为啥要在AAC中定义ViewModel这个类让我们继承呢?

这是因为,ViewModel组件的实例在config发生变化或者屏幕旋转时,不会被Activity/fragment重新创建,这个特性在我看来就是ViewModel组件最大以及唯一的意义,如果不是这个特性,我们完全可以用自己的实体类来替代google的ViewModel。或者反过来,我们也可以在学习了源码之后,在MVP中引入该机制,来让config变化时保存数据更容易。官方给出的ViewModel组件的生命周期图如下:
Android architecture components学习笔记2-ViewModel源码分析

可以看到,在Activity onCreate之后,ViewModel对象就被创建,而只有在Activity的finish方法调用后,ViewModel的onCleared方法被回调,之后才会销毁ViewModel对象,这是如何做到的呢?我们之后详细分析。

ViewModel使用示例

首先我们需要创建一个类继承自ViewModel,然后就没有然后了,我们可以将该类当做普通的Present或者VM来做我们自己想要的业务逻辑,官方示例中一般使用LiveData来传递数据,但是其实ViewModel组件和我们之前介绍的Lifecycle和之后要介绍的LiveData之间其实都不存在关系,我们完全可以在ViewModel中使用Rxjava甚至其他非观察者的方式来实现业务逻辑,说到底,ViewModel组件只是给我们提供了一个系统配置变化后保存数据的地方而已。

public class MyViewmodel extends ViewModel{
    //可以添加任意变量
    private String str = "text";
    //可以添加任意方法
    public String getStr(){
        return str;
    }
}

其次,我们在Activity或者fragment中通过ViewModelProviders获取到我们的MyViewModel实例,就可以向普通Present一样使用它了。注意获取方式是像示例中这样固定的方式,自己创建MyViewModel的对象,是达不到让系统保持数据的效果的。

public class MainActivity extends AppCompatActivity implements LifecycleObserver{
    @SuppressLint("RestrictedApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //固定套路获取我们自己的ViewModel
        MyViewmodel vm = ViewModelProviders.of(this)
                .get(MyViewmodel.class);
        //直接向Present一样使用其中的方法即可
        vm.getStr();
    }
}

ViewModel主要类

Android architecture components学习笔记2-ViewModel源码分析

我们首先来看一些ViewModel组件的主要类图,可以看到,主要的类并不多。ViewModel是我们需要继承的抽象类,ViewModelStore用来缓存创建的ViewMdodel对象,ViewModelStores是工具类,主要用于产生ViewModelStore。
ViewModelProvider中包含了ViewModelStore的引用,主要用于向外部提供ViewModel对象,ViewModelProviders是工具类,主要用于产生ViewModelProvider对象。

ViewModel

我们先来看看ViewModel类,毕竟我们之后都需要继承自它来编写自己的业务逻辑,可以看到,它是一个抽象类,内部只有一个空方法onCleared,在该类被销毁前调用。

public abstract class ViewModel {
    //该方法会在Activity finish时被调用
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }
}

ViewModelStore

该类是一个存储ViewModel的仓库,将ViewModel按照名称存储。我们可以方便的根据名称放入和取出ViewModel,我们来看一下代码:

public class ViewModelStore {
    //按照名称存储ViewModel
    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);
    }

    //调用每个ViewModel的onCleared回调方法,并清空map
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

可以看到,代码非常简单,其实就是用一个HashMap存储了名称和ViewModel的键值对,方便之后使用而已,没有什么好说的。

ViewModelProvider

该类的作用为根据我们传入的class对象,创建ViewModel实例并返回给我们,我们来看一下代码。

public class ViewModelProvider {
    public interface Factory {
        //根据传入的class对象,创建其ViewModel实例
        <T extends ViewModel> T create(Class<T> modelClass);
    }
    //Factory的一个实现类,使用class的newInstance方法创建ViewModel实例
    public static class NewInstanceFactory implements Factory {
        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            try {
                return modelClass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
    }
    //创建ViewModel实例的Factory对象
    private final Factory mFactory;
    //存储ViewModel实例的ViewModelStore对象
    private final ViewModelStore mViewModelStore;
    //构造方法
    public ViewModelProvider(ViewModelStore store, Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }

    //根据Class对象,获取对应的ViewModel对象
    public <T extends ViewModel> T get(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) {
        //根据名称,从ViewModelStore的缓存中获取ViewModel对象
        ViewModel viewModel = mViewModelStore.get(key);
        //如果获取成功了的话,直接返回。
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } 
        //如果缓存中没有,则使用Factory类创建
        viewModel = mFactory.create(modelClass);
        //将ViewModel加入缓存
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }
}

该类首先定义了一个Factory的接口,作用是根据传入的class产生实际的ViewModel对象,并且定义了一个该接口的默认实现类NewInstanceFactory,该类很简单,直接使用了class的newInstance方法构建一个对象,不多说了。

该类中有2个类成员变量,一个是Factory对象,用来创建ViewModel,一个是ViewModelStore,用来缓存ViewModel。我们来看看该类中最重要的get方法,就清楚了这2个成员变量的作用。

get方法的实现也比较简单,首先根据名称从ViewModelStore缓存中获取ViewModel,如果获取到的话,直接返回该ViewModel,如果缓存中没有的话,使用Factory对象新建一个ViewModel,并将其加入到ViewModelSote缓存中,就是一个很简单的缓存逻辑而已。

ViewModel流程分析

下面我们从ViewModel的使用示例中,来分析一下ViewModel组件的工作流程,还记得如果获得ViewModel对象么,很简单,在Activity中直接一行代码,轻松获取,见下面代码。

 MyViewmodel vm = ViewModelProviders.of(this).get(MyViewmodel.class);

当然啦,看起来简单的代码,实际未必简单,我们下面详细分析。

ViewModelProviders的of方法

我们来看一下of方法,首先创建一个单实例的DefaultFactory对象,该DefaultFactory对象是Factory接口的一个默认实现,该DefaultFactory针对AndroidViewModel类会使用带Application参数的构造器创建ViewModel对象,而对于普通ViewModel类,使用不带创建的构造器。然后使用ViewModelStore和DefaultFactory对象构建一个ViewModelProvider,并将其返回,这样就完成了of方法的工作,代码比较简单,并且已经对于较重要的步骤进行了注释,就不细说了。

public class ViewModelProviders{

    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        //创建默认的Factory实例
        initializeFactoryIfNeeded(activity.getApplication());
        //使用ViewModelStore和Factory构建ViewModelProvider对象,并返回结果。
        return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
    }

    //创建单实例的默认DefaultFactory对象
    private static void initializeFactoryIfNeeded(Application application) {
        //类似于单例模式,sDefaultFactory为空则创建
        if (sDefaultFactory == null) {
            sDefaultFactory = new DefaultFactory(application);
        }
    }

    //存储DefaultFactory的静态实例
    private static DefaultFactory sDefaultFactory;

    //默认Factory类,继承了我们之前说过的NewInstanceFactory
    public static class DefaultFactory extends ViewModelProvider.NewInstanceFactory {
    //保存Application对象
    private Application mApplication;

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

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        //如果ViewModel继承自AndroidViewModel类,则使用带Application参数的构造器创建对象
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            try {
                return modelClass.getConstructor(Application.class).newInstance(mApplication);
            } catch (Exception e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
        //否则使用不带参数构造器创建ViewModel对象
        return super.create(modelClass);
    }
}

ViewModelStores的of方法

上面我们分析ViewModelProviders的of方法在创建ViewModelProvider的实例时,调用了ViewModelStores类的of方法来获取一个ViewModelStore实例,我们就来分析一下它的of方法。

@MainThread
public static ViewModelStore of(FragmentActivity activity) {
    return holderFragmentFor(activity).getViewModelStore();
}

可以看到,代码很简单,就一句话搞定,我们看一下holderFragmentFor的实现,产生了一个HolderFragment,那是什么东东呢不明觉厉啊,我们赶紧跟过去看看再说。

HolderFragment类

HolderFragment类是一个Fragment,Fragment是大家平时常用的组件,只不过我们平时一般都是用它来展示ui,解耦Activity。而ViewModel这里给我们展示了Fragment的另一种用法,即完全没有ui界面,而是作为一个数据容器使用,那么这个数据容器装载的是什么呢?答案就是我们之前说的ViewModelStore。

对于每一个使用了ViewModel的Activity/Fragment,我们都将向它添加一个没有界面的HolderFragment,HolderFragment中包含一个ViewModelStore,其中按照名称存储了所有的VIewModel。也就是说我们使用的ViewModel都是从HolderFragment中拿出来的。

我们已经知道,我们最终使用的ViewModel保存在HolderFragment中,那么要想配置变化时,我们的ViewModel不被销毁,必须保证HolderFragment不会被销毁,这要如何做到呢?其实fragment中已经有这样的方法了,那就是setRetainInstance(true)方法,我们来看一下该方法的源码。

/**
     * Control whether a fragment instance is retained across Activity
     * re-creation (such as from a configuration change).  This can only
     * be used with fragments not in the back stack.  If set, the fragment
     * lifecycle will be slightly different when an activity is recreated:
     * <ul>
     * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
     * will be, because the fragment is being detached from its current activity).
     * <li> {@link #onCreate(Bundle)} will not be called since the fragment
     * is not being re-created.
     * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
     * still be called.
     * </ul>
     */
    public void setRetainInstance(boolean retain) {
        mRetainInstance = retain;
    }

该方法的实现虽然只有一句话,不过作用确很重要,我们看注释可以知道,如果该标志被设置为true,那么当Activity因为配置变化而重建时,该fragment的实例将会被保留,并且生命周期的onDestroy方法不会被调用。

上面我们已经从整体上说明了ViewModel为什么可以在配置变化时,保存数据的原理,下面我们来详细看看HolderFragment的源码,分析一下该过程具体的实现。

public class HolderFragment extends Fragment {
    //HolderFragment管理器对象,管理了所有HolderFragment的添加,获取等。
    private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final String HOLDER_TAG =
            "android.arch.lifecycle.state.StateProviderHolderFragment";
    //ViewModelStore对象,用来存储ViewModel
    private ViewModelStore mViewModelStore = new ViewModelStore();

    public HolderFragment() {
        //构建时,调用该方法,保证HolderFragment在配置变化导致Activity重建时,其实例不会被销毁重建
        setRetainInstance(true);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //通知HolderFragment管理器,自身已经创建成功了
        sHolderFragmentManager.holderFragmentCreated(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //HolderFragment销毁时,ViewModelStore中存储的ViewModel才会被销毁
        mViewModelStore.clear();
    }
    //返回我们存储的ViewModelStore对象
    public ViewModelStore getViewModelStore() {
        return mViewModelStore;
    }

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        //静态方法,返回HolderFragment对象
        return sHolderFragmentManager.holderFragmentFor(activity);
    }

    @SuppressWarnings("WeakerAccess")
    static class HolderFragmentManager {
        //该map存储了已经执行了Commit但是尚未添加到宿主Activity的HolderFragment,防止HolderFragment
        //重复添加。
        private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
        //Activity生命周期回调
        private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        //如果Activity在HolderFragment尚未添加成功时被销毁,
                        //则我们将它从尚未成功commit的map中移除
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                    }
                };
        //标志位,判断Application是否添加了生命周期监听器
        private boolean mActivityCallbacksIsAdded = false;

        //HolderFragment已经成功添加到宿主Activity了,我们将其从尚未成功map中移除
        void holderFragmentCreated(Fragment holderFragment) {
            Fragment parentFragment = holderFragment.getParentFragment();
            //省略部分内容
            mNotCommittedActivityHolders.remove(holderFragment.getActivity());
        }

        //根据HOLDER_TAG,从宿主Activity,fragment中查找对应的HolderFragment
        private static HolderFragment findHolderFragment(FragmentManager manager) {
            if (manager.isDestroyed()) {
                throw new IllegalStateException("Can't access ViewModels from onDestroy");
            }

            Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
            if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
                throw new IllegalStateException("Unexpected "
                        + "fragment instance was returned by HOLDER_TAG");
            }
            return (HolderFragment) fragmentByTag;
        }

        //创建HolderFragment并使用HOLDER_TAG将其添加到宿主Activity,fragment中
        private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
            HolderFragment holder = new HolderFragment();
            fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
            return holder;
        }

        //从宿主Activity中获取HolderFragment,如果没有则添加
        HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            //根据HOLDER_TAG标签,查找HolderFragment是否已经存在
            HolderFragment holder = findHolderFragment(fm);
            //如果存在直接返回。
            if (holder != null) {
                return holder;
            }
            //从已经Commit但是尚未成功添加到宿主Activity的map集合中查找该fragment
            holder = mNotCommittedActivityHolders.get(activity);
            //如果找到,则直接返回
            if (holder != null) {
                return holder;
            }
            //如果全局的Activity生命周期监听器尚未添加,则我们添加
            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            //创建HolderFragment,并将其加入map中
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;
        }
    }
}

HolderFragment的holderFragmentFor方法

首先我们来看获取HolderFragment的holderFragmentFor方法,该方法为静态方法,外部调用它来获取HolderFragment的实例,该方法直接调用了内部类HolderFragmentManager的同名方法,该内部类主要对所有的HolderFragment进行管理。

HolderFragmentManager的holderFragmentFor方法

我们继续看HolderFragmentManager的holderFragmentFor方法,可以看到,其执行流程如下:
1,使用一个HOLDER_TAG,从FragmentManager中查找HolderFragment是否已经添加了,如果找到,直接返回。
2,从mNotCommittedActivityHolders这个map中查找HolderFragment,如果找到,直接返回。
3,如果Application中没有添加Activity生命周期监听,添加生命周期间监听器。
4,使用HOLDER_TAG这个TAG,创建一个HolderFragment,并添加到宿主Activity中。
5,将该HolderFragment加入mNotCommittedActivityHolders这个map,并返回HolderFragment。
Android architecture components学习笔记2-ViewModel源码分析

通过这个方法,我们就完成了将HolderFragment添加到宿主Activity中,并且可以随时获取的功能,不过这里有一点疑问,那就是我们为何需要mNotCommittedActivityHolders这样一个key为Activity,值为HolderFragment的hashMap来保存HolderFragment呢?按道理,我们只要使用findFragmentByTag就可以找到我们添加的HolderFragment了啊。

原来我们将HolderFragment通过FragmentManager的commit方法添加了之后,HolderFragment并没有被立即添加到宿主Activity中,还需要系统执行一定的其他操作,而如果此时我们再执行HolderFragmentFor方法,这样对于同一个Activity就会创建多个HolderFragemnt实例,所以我们将它保存到map中,并且在HolderFragment真正onCreate的时候移除,这样就达到了一个宿主Activity只存在唯一的HolderFragment的目的。

HolderFragment的getViewModelStore

该方法很简单,返回内部创建的ViewModelStore,由于HolderFragment在配置变化时不会销毁,所以它内部的ViewModelStore也不会销毁,因此我们存储在其中的ViewModel自然也不会销毁啦。

流程总结

我们先看一下整体的流程图,大概分为如下几步:
1,ViewModelProviders工具类创建ViewModelProvider对象。
2,ViewModelStores工具类获取ViewModelStore对象。
3,创建HolderFragment,加入宿主Activity,并返回ViewModelStore对象。
4,ViewModelProvider使用Factory接口创建ViewModel对象,使用ViewModelStore缓存ViewModel对象。
Android architecture components学习笔记2-ViewModel源码分析

最后再附上一张时序图,上面标明了我们分析的所有类,以及ViewModel的主要流程方法,相信大家看了这张图之后,再看代码就会更清晰啦。
Android architecture components学习笔记2-ViewModel源码分析

ViewModel和onSaveInstance的区别

1,onSaveInstance适合保存少量数据,而ViewModel则可以保存较多的数据。
2,onSaveInstance保存的数据保存在系统进程中,因此如果用户app因内存不足被系统杀死时,onSaveInstance保存的数据还可以拿回来。而ViewModel保存的数据则消失了。
3,2者都只适合保存临时性的数据,如果想要持久化保存,请使用database或者文件。

实际使用

很多同学表示,自己习惯或者公司早就已经在使用比较成熟的mvp架构了,google的AAC虽然看起来不错,但是贸然切过去,成本和风险还是比较大的,感觉根本就没有机会使用啊。
这里其实我想说,AAC架构是独立的几个部分,哪怕我们不使用google推荐的mvvm架构,我们也还是可以*的使用Lifecycle和ViewModel啊,比如我们可以这样使用,先创建一个Present,让它继承自ViewModel类并且实LifecycleObserver接口。

public class Present extends ViewModel implements LifecycleObserver{

    public Present(){

    }

    public void test(){
        Log.d("Present"," i am a test");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate(){
        Log.d("Present"," onCreate");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(){
        Log.d("Present"," onDestroy");
    }
}

在Activity的onCreate方法中这样使用。这样岂不就即ViewModel组件提供的配置变化时,我们的Present不会被销毁的功能,又实现了Lifecycle组件提供的观察生命周期变化的功能了么。AAC的2个组件一下就派上了用场,而且还是在我们常用的mvp模式中,并不强制需要切换到mvvm模式,岂不美哉。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Present pm = ViewModelProviders.of(this)
            .get(Present.class);
    getLifecycle().addObserver(pm);
    pm.test();
}

当然啦,有同学可能要说,我们明明是mvp,但是需要继承自ViewModel,还要使用神马ViewModelProviders啦,不是很容易让人误解,感觉不明觉厉么。
那我只能说,少年,源码也有啦,分析也有啦,不想用现成的,直接自己造着源码撸一套不就行了么,反正也不复杂。

ViewModel设计思路借鉴

1,HolderFragment的使用,Fragment是我们平时常用的ui组件,我们一般用它来组织界面显示,达到复用的目的。而ViewModel向我们展示了Fragment的另外一种用法,即用来存储数据,而不是显示界面,作为一个数据容器使用。回想我们上篇讲过的Lifecycle,其ReportFragment也是不显示界面。我们发现,原来对fragment的理解还是太片面了。
2,Fragment的setRetainInstance方法,ViewModel组件虽然内容不少,但是核心还是该方法,让系统替我们保存fragment的实例,从而达到保存数据德目的。
3,使用一些静态工具类,例如ViewModelProviders,ViewModelStores来提供工厂方法创建实例,而不是直接提供构造方法创建实例,这样隐藏了创建对象的细节,便于抽象和管理。

相关标签: android 源码