美文网首页
Android-ViewModel原理解析

Android-ViewModel原理解析

作者: zzq_nene | 来源:发表于2020-12-26 18:29 被阅读0次

    一、ViewModel原理解析

    1.通过ViewModelProviders.of()方法创建ViewModel对象

    (1)public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory)
    (2)public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory)
    (3)public static ViewModelProvider of(@NonNull Fragment fragment)
    (4)public static ViewModelProvider of(@NonNull FragmentActivity activity)
    

    在这四个方法中,其实唯一的区别就是要不要传Factory,当没有传自定义的Factory的时候,则会传入默认的Factory,我们看ViewModelProvider构造器的源码和部分of方法的源码:

        public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
            this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                    ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                    : NewInstanceFactory.getInstance());
        }
    

    在ViewModelProvider中需要传入一个VieModelStore对象,这个对象是由ViewModelStoreOwner来提供的,而在Activity或者Fragment中,是由Activity和Fragment来提供的,因为ViewModelStoreOwner是一个接口,而AppCompatActivity的祖父ComponentActivity和Fragment均实现了ViewModelStoreOwner接口。

    但是ViewModelProviders在新的lifecycle-extensions库中,已经是属于被弃用的。新版的API直接使用ViewModelProvider,而不是ViewModelProviders。
    比如:

    viewModel = ViewModelProvider(this).get(TestViewModel::class.java)
    

    可以如下的方式在baseActivity中添加,由子类Activity调用:

        private lateinit var mActivityProvider: ViewModelProvider
        protected open fun <T : ViewModel?> getActivityViewModel(modelClass: Class<T>): T {
            // 如果使用lateinit,则不能进行判null,kotlin想要判断是否为null,需要使用?
            if (mActivityProvider == null) {
                mActivityProvider = ViewModelProvider(this)
            }
            return mActivityProvider.get(modelClass)
        }
    

    创建ViewModel对象,首先就需要先初始化一个ViewModelProvider对象

        public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
            this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                    ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                    : NewInstanceFactory.getInstance());
        }
    
        public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
            this(owner.getViewModelStore(), factory);
        }
    

    可以看出,ViewModelProvider构造函数其实最终都是需要两个参数,一个是ViewModelStoreOwner对象,一个是Factory。而ViewModelStoreOwner其实就是用来获取一个ViewModelStore对象来保存ViewModel对象的。而Factory就是用来创建ViewModel对象的。

    2.ViewModelStoreOwner接口:

    public interface ViewModelStoreOwner {
        /**
         * Returns owned {@link ViewModelStore}
         *
         * @return a {@code ViewModelStore}
         */
        @NonNull
        ViewModelStore getViewModelStore();
    }
    

    这个接口的主要实现的作用就是返回一个ViewModelStore对象。在Android中,Activity和Fragment都会实现该接口,并且实现getViewModelStore()方法。
    比如Activity就是在FragmentActivity的父类ComponentActivity中实现了ViewModelStoreOwner接口

    public class ComponentActivity extends androidx.core.app.ComponentActivity implements
            LifecycleOwner,
            ViewModelStoreOwner,
            HasDefaultViewModelProviderFactory,
            SavedStateRegistryOwner,
            OnBackPressedDispatcherOwner {
        ...
        @NonNull
        @Override
        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 nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    // Restore the ViewModelStore from NonConfigurationInstances
                    mViewModelStore = nc.viewModelStore;
                }
                if (mViewModelStore == null) {
                    mViewModelStore = new ViewModelStore();
                }
            }
            return mViewModelStore;
        }
        ...
    }
    
    public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
            ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner {
        ...
        @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            if (mFragmentManager == null) {
                throw new IllegalStateException("Can't access ViewModels from detached fragment");
            }
            return mFragmentManager.getViewModelStore(this);
        }
        ...
    }
    

    Fragment的ViewModelStore其实是由FragmentManager进行管理获取

    FragmentManager#getViewModelStore
        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            // 这里的mNonConfig是一个FragmentManagerViewModel对象
            return mNonConfig.getViewModelStore(f);
        }
    

    每个FragmentActivity都会有一个自己的FragmentManager对象,所以每个FragmentManagerViewModel对象,管理的是一个FragmentActivity中的所有的Fragment对应的ViewModel。具体看FragmentManagerViewModel的getViewModelStore方法

        @NonNull
        ViewModelStore getViewModelStore(@NonNull Fragment f) {
            ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
            if (viewModelStore == null) {
                viewModelStore = new ViewModelStore();
                mViewModelStores.put(f.mWho, viewModelStore);
            }
            return viewModelStore;
        }
    

    从这里可以看出,每个Fragment都会有自己的ViewModelStore对象,而ViewModelStore对象,是根据每个Fragment的唯一标识进行创建的。

    3.ViewModelStore类:

    public class ViewModelStore {
    
        private final HashMap<String, ViewModel> mMap = new HashMap<>();
    
        final void put(String key, ViewModel viewModel) {
            ViewModel oldViewModel = mMap.put(key, viewModel);
            if (oldViewModel != null) {
                oldViewModel.onCleared();
            }
        }
    
        final ViewModel get(String key) {
            return mMap.get(key);
        }
    
        Set<String> keys() {
            return new HashSet<>(mMap.keySet());
        }
    
        /**
         *  Clears internal storage and notifies ViewModels that they are no longer used.
         */
        public final void clear() {
            for (ViewModel vm : mMap.values()) {
                vm.clear();
            }
            mMap.clear();
        }
    }
    

    ViewModelStore类对象,是每个Activity或者Fragment都有一个,目的是用于保存该页面的ViewModel对象,方便ViewModel的管理

    4.ViewModelProvider的get方法:

        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull Class<T> 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);
        }
    
        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            ViewModel viewModel = mViewModelStore.get(key);
    
            if (modelClass.isInstance(viewModel)) {
                if (mFactory instanceof OnRequeryFactory) {
                    ((OnRequeryFactory) mFactory).onRequery(viewModel);
                }
                return (T) viewModel;
            } else {
                //noinspection StatementWithEmptyBody
                if (viewModel != null) {
                    // TODO: log a warning.
                }
            }
            if (mFactory instanceof KeyedFactory) {
                viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
            } else {
                viewModel = (mFactory).create(modelClass);
            }
            mViewModelStore.put(key, viewModel);
            return (T) viewModel;
        }
    

    从ViewModelProvider的get方法中,可以看出,get方法传入的是一个ViewModel.class的Class类型,然后通过这个类型,得到ViewModel的规范名称。将ViewModel对象缓存在ViewModelStore中的HashMap中。而ViewModel的创建,其实是通过ViewModelProvider.Factory来实现的

    5.ViewModelProviders类:

    ViewModelProviders的of方法,用于返回一个ViewModelProvider对象

        public static ViewModelProvider of(@NonNull FragmentActivity activity,
                @Nullable Factory factory) {
            if (factory == null) {
                factory = activity.getDefaultViewModelProviderFactory();
            }
            return new ViewModelProvider(activity.getViewModelStore(), factory);
        }
    

    从这里我们可以看到,如果传入的Activity或者Fragment有getDefaultViewModelProviderFactory方法实现,而factory为null的时候,则会通过getDefaultViewModelProviderFactory创建对应的Factory,而如果没有getDefaultViewModelProviderFactory的实现,那么就会调用NewInstanceFactory来创建对应的Factory,而NewInstanceFactory其实就是创建AndroidViewModelFactory对象。
    最终ViewModel对象,其实就是通过AndroidViewModelFactory的create的方法实现来创建。一般就是通过Class.newInstance或者Class.getConstructor来创建对象。

    而ViewModelProvider的第一个参数,其实最终传入的是ViewModelStore对象,这个对象内部是通过一个HashMap来保存ViewModel对象
    而新版的源码,ViewModelStore对象是通过Fragment和FragmentActivity对象的getViewModelStore方法来获取,而原先的HolderFragment的功能都移植到了Fragment中

        public class HolderFragment extends Fragment implements ViewModelStoreOwner {
            private static final String LOG_TAG = "ViewModelStores";
        
            // 这是什么?请看下面注释分析
            private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
        
            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment";
        
            // 这就是我们存放 ViewModel 的 ViewModelStore,就定义在 HolderFragment里
            private ViewModelStore mViewModelStore = new ViewModelStore();
        
            public HolderFragment() {
                // TODO: 为什么当 activity 由于屏幕旋转等被系统销毁时,
                // 这个 fragment 实例也不会被销毁?因为设置了 setRetainInstance(true)
                setRetainInstance(true);
            }
        
            @Override
            public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                // 当 Fragment 的 onCreate 方法执行,说明了 Fragment 已经成功添加到了 Activity,
                // sHolderFragmentManager 是 HolderFragmentManager类,它的 holderFragmentCreated()方法
                // 是将该 Fragment 从 mNotCommittedActivityHolders 或 mNotCommittedFragmentHolders 中移除
                // (HolderFragmentManager 的说明,请看下面的注释)
                sHolderFragmentManager.holderFragmentCreated(this);
            }
        
            @Override
            public void onSaveInstanceState(Bundle outState) {
                super.onSaveInstanceState(outState);
            }
        
            @Override
            public void onDestroy() {
                super.onDestroy();
                // 当一个设置了 setRetainInstance(true) 的 Fragment 的 onDestroy 方法被调用,
                // 证明它依附的 Activity 已经寿终正寝,所以调用 mViewModelStore.clear(),
                // 前面我们已经说了,这个 clear 方法会调用所有 ViewModel 对象的 onCleared 方法
                // 并且清空它们,我们可以在 ViewModel 的onCleared 方法做一些处理,以免起来不必要的
                // 内存泄漏等问题
                mViewModelStore.clear();
            }
        
            // 该方法用于给外部调用,返回 ViewModelStore
            @Override
            public ViewModelStore getViewModelStore() {
                return mViewModelStore;
            }
        
            // 静态方法,没 ViewModelStores.of 方法中被调用
            // 作用:在 activity 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
            public static HolderFragment holderFragmentFor(FragmentActivity activity) {
                return sHolderFragmentManager.holderFragmentFor(activity);
            }
        
            // 静态方法,没 ViewModelStores.of 方法中被调用
            // 作用:在 fragment 中添加一个 HolderFragment 用于存储存放了ViewModel对象的ViewModelStore
            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            public static HolderFragment holderFragmentFor(Fragment fragment) {
                return sHolderFragmentManager.holderFragmentFor(fragment);
            }
        
            // 上面的大部分操作都是基于HolderFragmentManager,我们来分析下这个类
            @SuppressWarnings("WeakerAccess")
            static class HolderFragmentManager {
        
                // 存放还没被系统正式添加到 Activity 中的 HolderFragment
                private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
                private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
        
                // 声明定义了一个能够感知 Activity 生命周期的 ActivityLifecycleCallbacks 
                private ActivityLifecycleCallbacks mActivityCallbacks =
                        new EmptyActivityLifecycleCallbacks() {
                            @Override
                            public void onActivityDestroyed(Activity activity) {
                                // 当 Activity destroy 的时候,清除 mNotCommittedActivityHolders 中保存
                                // 的对应 HolderFragment。前面我们分析了 HolderFragment 的 onCreate 方法中
                                // 会请一次 mNotCommittedActivityHolders,为什么在这么还要多此一举呢?其实
                                // 并不是多此一举,因为 Fragment 有可能还没创建完,Activity 就夭折了,那这样子
                                // HodlerFragment 的 onCreate 就无法调用,所以在加多一层清理机制,确保能够
                                // 清除掉(不得不感叹,谷歌官方的严谨以及对源码的掌控理解能力)
                                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) {
                                // 与 mActivityCallbacks 的分析同理
                                super.onFragmentDestroyed(fm, parentFragment);
                                HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                                        parentFragment);
                                if (fragment != null) {
                                    Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                                }
                            }
                        };
        
                // HolderFragment 的 onCreate 生命周期被回调,就会调用这个方法,清除
                // mNotCommittedActivityHolders 或者 mNotCommittedFragmentHolders 中
                // 的引用的 HolderFragment
                void holderFragmentCreated(Fragment holderFragment) {
                    Fragment parentFragment = holderFragment.getParentFragment();
                    if (parentFragment != null) {
                        mNotCommittedFragmentHolders.remove(parentFragment);
                        parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                                mParentDestroyedCallback);
                    } else {
                        mNotCommittedActivityHolders.remove(holderFragment.getActivity());
                    }
                }
        
                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;
                }
        
                private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
                    HolderFragment holder = new HolderFragment();
                    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
                    return holder;
                }
        
                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);
                    // 我们新添加 add 的 Fragment 并不会马上就执行添加完(也就是说,这个方法执行完成后,马上再
                    // 调用一次,上面的 findHolderFragment 会返回 null。但是这没有关系,因为接下来我们还可
                    // 从 mNotCommittedActivityHolders 获取到对应的实例),所以我们这里先把他放在
                    // mNotCommittedActivityHolders 中。Not Committed 表示 fragment 的 commit 还没有完成
                    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;
                }
            }
        }
    

    HolderFragment通过设置setRetainInstance(true),使得自身能够不受到屏幕旋转等configuration
    changes影响而存活,直到依附的Activity正常结束。
    因为HolderFragment的生命周期,ViewModelStore对象保存在HolderFragment中,而ViewModel又存储在ViewModelStore中,这就是为什么我们说ViewModel类能够让数据在屏幕旋转等配置信息改变导致UI重建的情况下不被销毁。

    6.根据Factory创建ViewModel

    ViewModelProvider的get方法:

        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            ViewModel viewModel = mViewModelStore.get(key);
    
            if (modelClass.isInstance(viewModel)) {
                if (mFactory instanceof OnRequeryFactory) {
                    ((OnRequeryFactory) mFactory).onRequery(viewModel);
                }
                return (T) viewModel;
            } else {
                //noinspection StatementWithEmptyBody
                if (viewModel != null) {
                    // TODO: log a warning.
                }
            }
            if (mFactory instanceof KeyedFactory) {
                viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
            } else {
                viewModel = (mFactory).create(modelClass);
            }
            mViewModelStore.put(key, viewModel);
            return (T) viewModel;
        }
    

    在ViewModel中,有两种Factory,Factory是的类型是由ViewModelProvider在初始化的时候创建的,所以是由ViewModelProvider决定Factory的类型。在ViewModelProvider中,有两种Factory,一种是默认的Factory,默认的Factory是通过在ComponentActivity或者Fragment中实现HasDefaultViewModelProviderFactory接口,然后在getDefaultViewModelProviderFactory()方法中初始化一个SavedStateViewModelFactory对象;另一种Factory则是NewInstanceFactory,这种是通过NewInstanceFactory.getInstance()的单例方式获取。

    (1)SavedStateViewModelFactory创建ViewModel

    其实就是通过ViewModel的Class对象,然后通过反射创建ViewModel对象,然后保存到ViewModelStore中的Map集合中
    从ViewModelProvider的get方法可以看出,在ViewModelProvider的get方法中会根据Factory的类型,进行不同方法的调用。SavedStateViewModelFactory是实现了ViewModelProvider.KeyedFactory接口的,所以在创建ViewModel的时候,调用的是SavedStateViewModelFactory的create方法。

        public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
            // 方法参数中的modelClass就是我们要创建的目标ViewModel的Class对象
            // 首先判断该ViewModel是否是AndroidViewModel类型
            boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
            Constructor<T> constructor;
            // 如果是AndroidViewModel类型的,则在初始化的时候需要加入Application对象
            if (isAndroidViewModel) {
                constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
            } else {
                constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
            }
            // doesn't need SavedStateHandle
            if (constructor == null) {
                return mFactory.create(modelClass);
            }
            SavedStateHandleController controller = SavedStateHandleController.create(
                    mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
            try {
                T viewmodel;
                if (isAndroidViewModel) {
                    viewmodel = constructor.newInstance(mApplication, controller.getHandle());
                } else {
                    viewmodel = constructor.newInstance(controller.getHandle());
                }
                viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
                return viewmodel;
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Failed to access " + modelClass, e);
            } catch (InstantiationException e) {
                throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException("An exception happened in constructor of "
                        + modelClass, e.getCause());
            }
        }
    

    AndroidViewModel和ViewModel的构造器参数Class

        private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
                SavedStateHandle.class};
        private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};
    

    ViewModel保存和恢复数据
    ComponentActivity和Fragment都将数据的保存和恢复逻辑转发给了SavedStateRegistryController。在在onCreate方法里通过调用performRestore来恢复数据,在onSaveInstanceState方法里通过调用performSave来保存数据。而SavedStateRegistryController中的SavedStateRegistry对象,就是实际进行数据的保存和恢复的,在SavedStateRegistry通过唯一的key获取到一个SavedStateProvider,而SavedStateProvider其实就是返回需要保存的数据,将对应的需要缓存的数据一一返回,然后保存在系统缓存时的回调到onSaveInstanceState的方法参数Bundle中进行保存。
    SavedStateRegistry.performSave()
    该方法是由ComponentActivity的onSaveInstanceState方法触发调用SavedStateRegistryController的performSave,进而调用的

        @MainThread
        void performSave(@NonNull Bundle outBundle) {
            // 从SavedStateProvider中取出要保存的数据
            Bundle components = new Bundle();
            if (mRestoredState != null) {
                components.putAll(mRestoredState);
            }
            for (Iterator<Map.Entry<String, SavedStateProvider>> it =
                    mComponents.iteratorWithAdditions(); it.hasNext(); ) {
                Map.Entry<String, SavedStateProvider> entry1 = it.next();
                components.putBundle(entry1.getKey(), entry1.getValue().saveState());
            }
            // outBundle其实就是Activity要保存的数据
            outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
        }
    

    在SavedStateRegistry恢复数据的时候,会把恢复后的数据都交给SavedStateHandle。希望保留的数据,可以通过两种方式向mRegular保存数据。

    1.通过调用 set(@NonNull String key, @Nullable T value) 方法来实现,该方法就类似于 Map.put(Key,Value) 的方式来存值,但是这种方式并不具备数据变化通知
    2.通过 MutableLiveData.setValue的方式来存值。首先通过 getLiveData(@NonNull String key) 方法拿到和特定 Key 绑定的 LiveData 对象,之后向该 LiveData.setValue 时都会同时更新 mRegular

    在ComponentActivity恢复数据的时候,会通过SavedStateRegistryController.performSave在Activity的onSaveInstanceState方法中进行数据的保存,然后在ComponentActivity的onCreate方法中,通过调用SavedStateRegistryController.performRestore方法进行数据的恢复,这些恢复的数据都会保存在SavedStateHandleController对象中的SavedStateHandle属性中,然后在Activity重新创建的时候,会通过反射创建对应的ViewModel对象的时候,将SavedStateHandleController中的SavedStateHandle赋值给对应的ViewModel进行数据恢复。

    这块的源码分析可以参考:
    从源码看 Jetpack(7)-SavedStateHandle源码详解

    (2)NewInstanceFactory创建ViewModel
            @NonNull
            @Override
            public <T extends ViewModel> T create(@NonNull Class<T> 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);
                }
            }
    

    这里其实就是直接使用Class的newInstance直接创建对象。Activity和Fragment一般都是使用SavedStateViewModelFactory创建ViewModel对象。

    二、ViewModel的销毁

    ViewModel的销毁,要分为Activity和Fragment两部分。
    首先看下ViewModel在销毁的时候做的事情

        protected void onCleared() {
        }
    
        @MainThread
        final void clear() {
            mCleared = true;
            // Since clear() is final, this method is still called on mock objects
            // and in those cases, mBagOfTags is null. It'll always be empty though
            // because setTagIfAbsent and getTag are not final so we can skip
            // clearing it
            if (mBagOfTags != null) {
                synchronized (mBagOfTags) {
                    for (Object value : mBagOfTags.values()) {
                        // see comment for the similar call in setTagIfAbsent
                        closeWithRuntimeException(value);
                    }
                }
            }
            onCleared();
        }
    

    而ViewModel的clear()方法的调用,是在ViewModelStore中

        public final void clear() {
            for (ViewModel vm : mMap.values()) {
                vm.clear();
            }
            mMap.clear();
        }
    

    1.Activity中的销毁

    Activity的销毁,是通过Lifecycle监听生命周期回调,当生命周期执行到onDestroy的时候,调用ViewModelStore的clear()方法进行ViewModel的销毁。
    看ComponentActivity中构造器中的实现:

            getLifecycle().addObserver(new LifecycleEventObserver() {
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source,
                        @NonNull Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        // 这里是判断是否是系统配置发生变化,比如手机屏幕旋转
                        // 这里的配置是在Activity的onStop()方法中进行修改的
                        if (!isChangingConfigurations()) {
                            getViewModelStore().clear();
                        }
                    }
                }
            });
    
        protected void onStop() {
            if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
            if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
            mActivityTransitionState.onStop();
            dispatchActivityStopped();
            mTranslucentCallback = null;
            mCalled = true;
    
            if (mAutoFillResetNeeded) {
                // If stopped without changing the configurations, the response should expire.
                getAutofillManager().onInvisibleForAutofill(!mChangingConfigurations);
            } else if (mIntent != null
                    && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
                    && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
                restoreAutofillSaveUi();
            }
            mEnterAnimationComplete = false;
        }
    

    Fragment中的销毁

    Fragment的生命周期管理,如下:

        static final int INITIALIZING = -1;    // Not yet attached.
        static final int ATTACHED = 0;         // Attached to the host.
        static final int CREATED = 1;          // Created.
        static final int ACTIVITY_CREATED = 2; // Fully created, not started.
        static final int STARTED = 3;          // Created and started, not resumed.
        static final int RESUMED = 4;          // Created started and resumed.
    

    Fragment的生命周期,首先会依次增大,然后在从onResume变成onPause的时候,就开始状态码减小。即先升再降的一个状态变化。在当前状态码变成CREATED的时候,就会执行onDestroy。即调用

    fragmentStateManager.destroy(mHost, mNonConfig);
    

    FragmentStateManager.destroy

        void destroy(@NonNull FragmentHostCallback<?> host,
                @NonNull FragmentManagerViewModel nonConfig) {
            if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                Log.d(TAG, "movefrom CREATED: " + mFragment);
            }
            boolean beingRemoved = mFragment.mRemoving && !mFragment.isInBackStack();
            boolean shouldDestroy = beingRemoved || nonConfig.shouldDestroy(mFragment);
            if (shouldDestroy) {
                boolean shouldClear;
                if (host instanceof ViewModelStoreOwner) {
                    shouldClear = nonConfig.isCleared();
                } else if (host.getContext() instanceof Activity) {
                    Activity activity = (Activity) host.getContext();
                    shouldClear = !activity.isChangingConfigurations();
                } else {
                    shouldClear = true;
                }
                if (beingRemoved || shouldClear) {
                    nonConfig.clearNonConfigState(mFragment);
                }
                mFragment.performDestroy();
                mDispatcher.dispatchOnFragmentDestroyed(mFragment, false);
            } else {
                mFragment.mState = Fragment.ATTACHED;
            }
        }
    

    在这里就会调用nonConfig.clearNonConfigState方法,nonConfig其实就是FragmentManagerViewModel对象。
    FragmentManagerViewModel.clearNonConfigState

        void clearNonConfigState(@NonNull Fragment f) {
            if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                Log.d(TAG, "Clearing non-config state for " + f);
            }
            // Clear and remove the Fragment's child non config state
            FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
            if (childNonConfig != null) {
                childNonConfig.onCleared();
                mChildNonConfigs.remove(f.mWho);
            }
            // Clear and remove the Fragment's ViewModelStore
            ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
            if (viewModelStore != null) {
                viewModelStore.clear();
                mViewModelStores.remove(f.mWho);
            }
        }
    

    三、ViewModel生命周期绑定

    按照上面的逻辑,在Activity重建时会执行destory生命周期事件,那么为什么ViewModel没有销毁呢?
    其实就是在屏幕旋转的时候,AMS通过Binder回调Activity的retainNonConfigurationInstances()方法,这个时候就会进行数据的保存,保存到一个NonConfigurationInstances对象;而在屏幕翻转结束之后,会再一次调用ViewModelProvider的构造函数,此时就会调用owner.getViewModelStore(),接着就会调用getLastNonConfigurationInstance(),这里就会通过Activity中的NonConfigurationInstances对象取出保存的ViewModelStore对象。
    所以数据保存就是通过retainNonConfigurationInstances()方法保存在NonConfigurationInstances对象,而再一次使用取出ViewModel的数据的时候,就是从nc对象中取出ViewModelStore对象,而ViewModelStore对象保存有ViewModel集合
    通过对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 nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    // Restore the ViewModelStore from NonConfigurationInstances
                    mViewModelStore = nc.viewModelStore;
                }
                if (mViewModelStore == null) {
                    mViewModelStore = new ViewModelStore();
                }
            }
            return mViewModelStore;
        }
    

    当mViewModelStore为null的时候,会从NonConfigurationInstances中获取ViewModelStore对象。
    其实在ComponentActivity和Activity中都会有一个NonConfigurationInstances类,而Activity中的NonConfigurationInstances类结构如下:

        static final class NonConfigurationInstances {
            Object activity;
            HashMap<String, Object> children;
            FragmentManagerNonConfig fragments;
            ArrayMap<String, LoaderManager> loaders;
            VoiceInteractor voiceInteractor;
        }
    

    这里的Object activity其实就是保存的ComponentActivity中的NonConfigurationInstances类对象,看Activity的下面的方法:

        // TODO: retainNonConfigurationInstances()方法,其实是在AMS通过Binder跨进程调用的
        // 这是在ActivityThread的performDestroyActivity方法调用
        // 而在handleDestroyActivity的时候调用performDestroyActivity
        // 而handleRelaunchActivityInner会调用handleDestroyActivity,getNonConfigInstance会传入true
        // handleRelaunchActivityInner是在Activity重新启用的时候被调用
        // 其实就是旋转的时候,Activity就会被重启,这样就会最终触发retainNonConfigurationInstances()
        NonConfigurationInstances retainNonConfigurationInstances() {
            Object activity = onRetainNonConfigurationInstance();
            HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
            FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
    
            // We're already stopped but we've been asked to retain.
            // Our fragments are taken care of but we need to mark the loaders for retention.
            // In order to do this correctly we need to restart the loaders first before
            // handing them off to the next activity.
            mFragments.doLoaderStart();
            mFragments.doLoaderStop(true);
            ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
    
            if (activity == null && children == null && fragments == null && loaders == null
                    && mVoiceInteractor == null) {
                return null;
            }
    
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.activity = activity;
            nci.children = children;
            nci.fragments = fragments;
            nci.loaders = loaders;
            if (mVoiceInteractor != null) {
                mVoiceInteractor.retainInstance();
                nci.voiceInteractor = mVoiceInteractor;
            }
            return nci;
        }
    

    activity这个Object对象,其实是通过onRetainNonConfigurationInstance()方法返回值赋值,而onRetainNonConfigurationInstance()方法的实现是在ComponentActivity中。
    看ComponentActivity中的下面方法:

        public final Object onRetainNonConfigurationInstance() {
            Object custom = onRetainCustomNonConfigurationInstance();
    
            ViewModelStore viewModelStore = mViewModelStore;
            if (viewModelStore == null) {
                // No one called getViewModelStore(), so see if there was an existing
                // ViewModelStore from our last NonConfigurationInstance
                NonConfigurationInstances nc =
                        (NonConfigurationInstances) getLastNonConfigurationInstance();
                if (nc != null) {
                    viewModelStore = nc.viewModelStore;
                }
            }
    
            if (viewModelStore == null && custom == null) {
                return null;
            }
    
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.custom = custom;
            nci.viewModelStore = viewModelStore;
            return nci;
        }
    

    因为这里会在ComponentActivity中的NonConfigurationInstances类对象中保存ViewModelStore对象,所以这也是Activity重建时不会销毁ViewModel的原因。

    Activity的onRetainNonConfigurationInstance()的调用

    onRetainNonConfigurationInstance()方法除了被Activity的retainNonConfigurationInstances()调用以外,还会被LocalActivityManager的dispatchRetainNonConfigurationInstance()方法调用

    //在每个子活动上调用onRetainNonConfigurationInstance并将结果按ID存储在HashMap中。 
    //仅当存在要存储的非null对象时,才构造HashMap。 
    //请注意,这不支持嵌套的ActivityGroup。
        public HashMap<String,Object> dispatchRetainNonConfigurationInstance() {
            HashMap<String,Object> instanceMap = null;
            
            final int N = mActivityArray.size();
            for (int i=0; i<N; i++) {
                LocalActivityRecord r = mActivityArray.get(i);
                if ((r != null) && (r.activity != null)) {
                    Object instance = r.activity.onRetainNonConfigurationInstance();
                    if (instance != null) {
                        if (instanceMap == null) {
                            instanceMap = new HashMap<String,Object>();
                        }
                        instanceMap.put(r.id, instance);
                    }
                }
            }
            return instanceMap;
        }
    

    四、Fragment之间共享ViewModel

    在分析ViewModel的销毁过程时,我们看到Activity与Fragment存储VieModel是分离的,那么同一个Activity下的Fragment是如何共享ViewModel的呢?
    其实共享的是Activity的ViewModel。

    而具体的实现逻辑,其实就是在FragmentViewModelLazy.kt中的:

    @MainThread
    inline fun <reified VM : ViewModel> Fragment.activityViewModels(
        noinline factoryProducer: (() -> Factory)? = null
    ) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
        factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
    

    在Fragment中可以直接调用,这是一个Fragment的扩展函数,通过实现requireActivity().viewModelStore,获取到了Activity的ViewModelStore对象后,这样就可以实现了Fragment共用Activity的ViewModel,从而实现了Fragment之间共享ViewModel。
    Fragment之间共享ViewModel,需要引入

    "androidx.fragment:fragment-ktx:1.2.5"
    

    相关文章

      网友评论

          本文标题:Android-ViewModel原理解析

          本文链接:https://www.haomeiwen.com/subject/ejjmzhtx.html