android架构组件之ViewModel

ViewModel所解决的问题

      对于当前的界面,可能由于配置、旋转或是其他的原因导致当前的界面异常销毁,当出现这种情况时,界面恢复时也同时需要恢复一些数据,之前的做法就是利用onSaveInstanceState()在异常销毁时将数据保存起来,然后在页面重新启动时通过onRestoreInstanceState()对数据进行恢复,这种做法通常是对于一些简单的数据进行保存。现假如当前界面有个网络请求,当界面异常销毁后重新创建时不在进行网络请求,而是直接使用上一次请求的数据,这时该怎么去做呢?这时就需要使用到这里的主角ViewModel了。

ViewModel定义

       现在来看看ViewModel是如何定义:

public abstract class ViewModel {
    /**
     * This method will be called when this ViewModel is no longer used and will be destroyed.
     * 

* It is useful when ViewModel observes some data and you need to clear this subscription to * prevent a leak of this ViewModel. */ @SuppressWarnings("WeakerAccess") protected void onCleared() { } }

       还是很简单的,里面就是定义了一个方法,这个方法会在onDestroy()中被调用,所以这个方法里可以做一些释放资源的工作,他有一个实现类AndroidViewModel,这个类主要是提供了一个全局的Application,这样就可以在这个类中使用全局上下文了。

ViewModel使用 

       首先是定义一个继承ViewModel(如果需要Application,可以继承AndroidViewModel)类,如下:

public class CustomViewModel extends ViewModel {
    public MutableLiveData> listData = new MutableLiveData<>();
    public void getListData(){
        //假设这里是一个网络请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(3);
                    ArrayList list = new ArrayList();
                    for (int i = 0; i < 10;i++) {
                        list.add("string data index = "+i);
                    }
                    listData.postValue(list);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

这里需要你知道对LiveData的使用,这里使用延时模拟定义了一个网络请求,在三秒后将数据返回,这里定义完ViewModel后并不能实现一开始所说的对数据的保存,那还要怎么做呢?接下来就是重点了,为了达到一开始所说的效果,这里就需要说到Google提供的一个扩展库了,引入:

implementation 'android.arch.lifecycle:extensions:1.1.1'

用法如下:

CustomViewModel model = ViewModelProviders.of(this).get(HomeModel.class)

这个扩展库的作用就是为我们创建ViewModel对象并维护,用法很简单,接下来的重点就是去分析它是如何帮我们维护这个ViewModel对象的。

ViewModel是如何维护的

       这里的切入自然是ViewModelProviders这个类了,这个一个工厂类,这里要看的就是他的of()方法,这里需要传入的对象是FragmentActivity/Fragment,先来看下这个类的定义:

public class ViewModelProviders {

    /**
     * @deprecated This class should not be directly instantiated
     */
    @Deprecated
    public ViewModelProviders() {
    }

    private static Application checkApplication(Activity activity) {
        Application application = activity.getApplication();
        if (application == null) {
            throw new IllegalStateException("Your activity/fragment is not yet attached to "
                    + "Application. You can't request ViewModel before onCreate call.");
        }
        return application;
    }

    private static Activity checkActivity(Fragment fragment) {
        Activity activity = fragment.getActivity();
        if (activity == null) {
            throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
        }
        return activity;
    }

    /**
     * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given
     * {@code fragment} is alive. More detailed explanation is in {@link ViewModel}.
     * 

* It uses {@link ViewModelProvider.AndroidViewModelFactory} to instantiate new ViewModels. * * @param fragment a fragment, in whose scope ViewModels should be retained * @return a ViewModelProvider instance */ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment) { return of(fragment, null); } /** * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity * is alive. More detailed explanation is in {@link ViewModel}. *

* It uses {@link ViewModelProvider.AndroidViewModelFactory} to instantiate new ViewModels. * * @param activity an activity, in whose scope ViewModels should be retained * @return a ViewModelProvider instance */ @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) { return of(activity, null); } /** * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given * {@code fragment} is alive. More detailed explanation is in {@link ViewModel}. *

* It uses the given {@link Factory} to instantiate new ViewModels. * * @param fragment a fragment, in whose scope ViewModels should be retained * @param factory a {@code Factory} to instantiate new ViewModels * @return a ViewModelProvider instance */ @NonNull @MainThread public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) { Application application = checkApplication(checkActivity(fragment)); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(ViewModelStores.of(fragment), factory); } /** * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity * is alive. More detailed explanation is in {@link ViewModel}. *

* It uses the given {@link Factory} to instantiate new ViewModels. * * @param activity an activity, in whose scope ViewModels should be retained * @param factory a {@code Factory} to instantiate new ViewModels * @return a ViewModelProvider instance */ @NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(ViewModelStores.of(activity), factory); } /** * {@link Factory} which may create {@link AndroidViewModel} and * {@link ViewModel}, which have an empty constructor. * * @deprecated Use {@link ViewModelProvider.AndroidViewModelFactory} */ @SuppressWarnings("WeakerAccess") @Deprecated public static class DefaultFactory extends ViewModelProvider.AndroidViewModelFactory { /** * Creates a {@code AndroidViewModelFactory} * * @param application an application to pass in {@link AndroidViewModel} * @deprecated Use {@link ViewModelProvider.AndroidViewModelFactory} or * {@link ViewModelProvider.AndroidViewModelFactory#getInstance(Application)}. */ @Deprecated public DefaultFactory(@NonNull Application application) { super(application); } } }

代码比较简单,可以分为三步理解:

  1. 验证当前Fragment是否含有Activity,当前Activity是否含有全局上下文(Application);
  2. 创建Factory,这里默认的是上面的DeFaultFactory这个内部类,继承自ViewModelProvider.AndroidViewModelFactory,它的职责就是通过反射来创建ViewModel对象;
  3. 创建ViewModelProvider对象,它的第一个参数是ViewModelStores.of(activity),返回的是ViewModelStore对象,里面存储的是ViewModel对象,恢复的时候就是通过这个对象来取出的;

接下来就来分析第二点和第三点,先来看ViewModelProvider.AndroidViewModelFactory这个类:

    /**
     * {@link Factory} which may create {@link AndroidViewModel} and
     * {@link ViewModel}, which have an empty constructor.
     */
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;

        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public  T create(@NonNull Class 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);
        }
    }


    /**
     * Simple factory, which calls empty constructor on the give class.
     */
    public static class NewInstanceFactory implements Factory {

        @SuppressWarnings("ClassNewInstance")
        @NonNull
        @Override
        public  T create(@NonNull Class modelClass) {
            //noinspection TryWithIdenticalCatches
            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);
            }
        }
    }

是一个单例对象,这里主要是看它的create()方法,可以看到这里主要是利用反射构建了ViewModel对象。接着就要看看ViewModelProvider 的get()方法是如何返回ViewModel对象的:

public class ViewModelProvider {

    private static final String DEFAULT_KEY =
            "android.arch.lifecycle.ViewModelProvider.DefaultKey";

    /**
     * Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
     */
    public interface Factory {
        /**
         * Creates a new instance of the given {@code Class}.
         * 

* * @param modelClass a {@code Class} whose instance is requested * @param The type parameter for the ViewModel. * @return a newly created ViewModel */ @NonNull T create(@NonNull Class modelClass); } private final Factory mFactory; private final ViewModelStore mViewModelStore; /** * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given * {@code Factory} and retain them in a store of the given {@code ViewModelStoreOwner}. * * @param owner a {@code ViewModelStoreOwner} whose {@link ViewModelStore} will be used to * retain {@code ViewModels} * @param factory a {@code Factory} which will be used to instantiate * new {@code ViewModels} */ public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) { this(owner.getViewModelStore(), factory); } /** * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given * {@code Factory} and retain them in the given {@code store}. * * @param store {@code ViewModelStore} where ViewModels will be stored. * @param factory factory a {@code Factory} which will be used to instantiate * new {@code ViewModels} */ public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; this.mViewModelStore = store; } /** * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or * an activity), associated with this {@code ViewModelProvider}. *

* The created ViewModel is associated with the given scope and will be retained * as long as the scope is alive (e.g. if it is an activity, until it is * finished or process is killed). * * @param modelClass The class of the ViewModel to create an instance of it if it is not * present. * @param The type parameter for the ViewModel. * @return A ViewModel that is an instance of the given type {@code T}. */ @NonNull @MainThread public T get(@NonNull Class modelClass) { String canonicalName = modelClass.getCanonicalName(); if (canonicalName == null) { throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels"); } return get(DEFAULT_KEY + ":" + canonicalName, modelClass); } /** * Returns an existing ViewModel or creates a new one in the scope (usually, a fragment or * an activity), associated with this {@code ViewModelProvider}. *

* The created ViewModel is associated with the given scope and will be retained * as long as the scope is alive (e.g. if it is an activity, until it is * finished or process is killed). * * @param key The key to use to identify the ViewModel. * @param modelClass The class of the ViewModel to create an instance of it if it is not * present. * @param The type parameter for the ViewModel. * @return A ViewModel that is an instance of the given type {@code T}. */ @NonNull @MainThread public T get(@NonNull String key, @NonNull Class modelClass) { //如果之前添加过,那么就可以从集合中获取 ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { //noinspection unchecked return (T) viewModel; } else { //noinspection StatementWithEmptyBody if (viewModel != null) { // TODO: log a warning. } } //根据传进来的类创建对象并添加到集合中 viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; } }

重点看下这里的get()方法,可以看到这里获取ViewModel的一个流程:

  1. 从mViewModelStore中获取,它里面维护的就是一个HashMap;
  2. 没有获取到,就通过构造方法传进来的工厂对象反射进行创建,这里的工厂对象上面已经说了;

接着来看通过构造方法传进来的mViewModelStore对象,这个对象是通过ViewModelStores.of(activity)返回的,来看下这个类:

public class ViewModelStores {

    private ViewModelStores() {
    }

    /**
     * Returns the {@link ViewModelStore} of the given activity.
     *
     * @param activity an activity whose {@code ViewModelStore} is requested
     * @return a {@code ViewModelStore}
     */
    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }

    /**
     * Returns the {@link ViewModelStore} of the given fragment.
     *
     * @param fragment a fragment whose {@code ViewModelStore} is requested
     * @return a {@code ViewModelStore}
     */
    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }
}

这里会调用holderFragmentFor(activity).getViewModelStore()进行返回,holderFragmentFor()是HolderFragment类中的方法,而HolderFragment继承自Fragment,这里就是实现Activity异常销毁重新创建时恢复数据的关键,现在就来重点关注下这个类的实现,整个过程将在代码中进行讲解:

public class HolderFragment extends Fragment implements ViewModelStoreOwner {
    private static final String LOG_TAG = "ViewModelStores";

    private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final String HOLDER_TAG =
            "android.arch.lifecycle.state.StateProviderHolderFragment";

    //这里保存的就是ViewModel对象
    private ViewModelStore mViewModelStore = new ViewModelStore();

    public HolderFragment() {
        setRetainInstance(true);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sHolderFragmentManager.holderFragmentCreated(this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mViewModelStore.clear();
    }

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        return mViewModelStore;
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        //使用了代理的方式,那就去看看sHolderFragmentManager
        return sHolderFragmentManager.holderFragmentFor(activity);
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

    @SuppressWarnings("WeakerAccess")
    static class HolderFragmentManager {
        //维护了两个集合,根据不同的情况来进行保存HolderFragment
        private Map mNotCommittedActivityHolders = new HashMap<>();
        private Map mNotCommittedFragmentHolders = new HashMap<>();

        private ActivityLifecycleCallbacks mActivityCallbacks =
                new EmptyActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        //当activity退出时,需要及时清理,不然会导致内存泄露
                        HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                        }
                    }
                };

        private boolean mActivityCallbacksIsAdded = false;

        private FragmentLifecycleCallbacks mParentDestroyedCallback =
                new FragmentLifecycleCallbacks() {
                    @Override
                    public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                        super.onFragmentDestroyed(fm, parentFragment);
                        //fragment销毁时需要及时清理掉保存的HolderFragment,以免内存泄露
                        HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                                parentFragment);
                        if (fragment != null) {
                            Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                        }
                    }
                };

        //当调用fragment的onCreate()时会调用到这里,移除可能还保存的HolderFragment对象
        void holderFragmentCreated(Fragment holderFragment) {
            Fragment parentFragment = holderFragment.getParentFragment();
            if (parentFragment != null) {
                mNotCommittedFragmentHolders.remove(parentFragment);
                parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                        mParentDestroyedCallback);
            } else {
                mNotCommittedActivityHolders.remove(holderFragment.getActivity());
            }
        }

        //根据FragmentManager中是否保存了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对象并添加到FragmentManager中
        private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
            HolderFragment holder = new HolderFragment();
            fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
            return holder;
        }

        //这里就是去获取HolderFragment对象,
        HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }

            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            holder = createHolderFragment(fm);
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;
        }

        HolderFragment holderFragmentFor(Fragment parentFragment) {
            FragmentManager fm = parentFragment.getChildFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedFragmentHolders.get(parentFragment);
            if (holder != null) {
                return holder;
            }

            parentFragment.getFragmentManager()
                    .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
            holder = createHolderFragment(fm);
            mNotCommittedFragmentHolders.put(parentFragment, holder);
            return holder;
        }
    }
}

代码量不多,如果对fragment比较了解的话也比较好了解,这里有个fragment的方法setRetainInstance()需要知道,当这里传入的是true时,那么当Activity异常销毁时,fragment会进行保存,当下次activity重新创建时,会直接使用这个fragment而不会重新创建,HolderFragment中有个变量mViewModelStore,它里面存放的ViewModel,所以,当activity重新创建并获取ViewModel时,并不会在次去创建ViewModel对象,这样就可以直接使用ViewModel中存放的数据了。

总结:

      就是利用了fragment的setRetainInstance(true)特性。

      第一次通过ViewModelProviders创建ViewModel时,会先创建一个HolderFragment,并会将它添加FragmentManager中去,它里面还有一个mViewModelStore变量,主要作用就是用来存放ViewModel对象的,之后再通过反射创建一个ViewModel对象,并将这个对象添加到HolderFragment的mViewModelStore(内部维护的是一个HashMap)中,可以这样理解,只要这个HolderFragment存在,那么它维护的ViewHolder就不会重新创建,所以Activity异常销毁后重新创建只要保证HolderFragment不变就可以,这时setRetainInstance(true)就起到了这个作用。利用这个特性,可以使用ViewModel在activity和fragment之间进行数据传输。

 

 

 

 

 

 

 

你可能感兴趣的:(Android,android源码解析)