美文网首页
ViewModel源码分析

ViewModel源码分析

作者: hero123 | 来源:发表于2018-11-26 17:37 被阅读0次

ViewModel是什么?ViewModel是负责管理Activity和Fragment的数据的类,他独立于Activity和Fragment之外,即使Activity和Fragment因为屏幕旋转等原因销毁,只要Activity与Fragment重新创建,即可与原先的ViewModel重新绑定。首先查看ViewModel的获取方式:
val viewModel = ViewModelProviders.of(target, factory).get(PlanViewModel::class.java)
ViewModelProviders.of()方法获取ViewModelProvider的实例,然后通过get()方法获取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)) {
            //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;
    }

ViewModelProvider.get(key, class)方法,先查询要获取的viewmodel实例是否已经在ViewModelStroe中,如果实例已经存在于ViewModelStore中,则返回之前的实例,否则通过ViewModelProvider.Factory创建一个viewModel实例,并存放于viewModel中,下次再获取该类型的viewModel时,只要是同一个ViewModelStroe,就可以将缓存的viewModel返回。那么如何保证即使Activity重新创建后,获取到viewModel还是之前的ViewModel呢?由于ViewModelStroe内部仅仅是通过Map去管理ViewModel的缓存,所以只有保证Activity销毁重建后,ViewModelStroe是同一个,即可保证拿到的是原来的ViewModel。ViewModelStroe是从哪里来的呢?
继续看ViewModelProviders.of()的实现:

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(fragment.getViewModelStore(), factory);
    }
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(activity.getViewModelStore(), factory);
    }

通过of方法的实现可以看到ViewModelStore由实现了ViewModelStoreOwner的Activity和Fragment提供,下面分2部分分别去查看Activity和Fragment的实现;

Activity是如何管理ViewModelStore的

Activity都重新创建了,activity是如何保证ViewModelStore还是原来的呢?
下面看Activity.getViewModelStroe的实现:

ComponentActivity.java
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;
    }

Activity通过NonConfigurationInstances 实现对ViewModelStore的管理,显示获取最后的NonConfigurationInstances 实例,然后将NonConfigurationInstances.viewModelStore赋值给自己,这个NonConfigurationInstances.viewModelStore就是Activity销毁重建前的ViewModelStore

public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

到这里又看到一个NonConfigurationInstances,这里有点迷惑性,getViewModelStore里的NonConfigurationInstances是ComponentActivity.NonConfigurationInstances,getLastNonConfigurationInstance里的是Activity.NonConfigurationInstances,ComponentActivity.NonConfigurationInstances管理ViewModelStore,而Activity.NonConfigurationInstances则管理ComponentActivity.NonConfigurationInstances。接下来继续看getLastNonConfigurationInstance(),这个mLastNonConfigurationInstances 是在哪里创建的呢?是在activity.attach()里作为参数从外界传入的。activity.attch()则是在ActivityThread.performLaunchActivity()里被调用。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
        ...
        return activity;
}

继续追踪到ActivityThread.performLaunchActivity,可以看到,Activity.lastNonConfigurationInstances来源于ActivityClientRecord.lastNonConfigurationInstances,那么ActivityClientRecord.lastNonConfigurationInstances是什么时候被赋值的呢?答案是在activity销毁的时候,我们继续看ActivityThread.performDestroyActivity():

ActivityThread.performDestroyActivity() {
    if (getNonConfigInstance) {
                try {
                    r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
                } catch (Exception e) {
                    if (!mInstrumentation.onException(r.activity, e)) {
                        throw new RuntimeException(
                                "Unable to retain activity "
                                + r.intent.getComponent().toShortString()
                                + ": " + e.toString(), e);
                    }
                }
            }
}

在ActivityThread.performDestroyActivity() 中将Activity.retainNonConfigurationInstances()返回值赋给ActivityClientRecord.lastNonConfigurationInstances,继续看Activity.retainNonConfigurationInstances():

NonConfigurationInstances retainNonConfigurationInstances() {
        Object activity = onRetainNonConfigurationInstance();
        HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
        //获取Fragment的mNonConfig快照信息,用于重新恢复Fragment
        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;
    }

在retainNonConfigurationInstances()中,会创建返回一个Activity.NonConfigurationInstance实例,并且在里边看到熟悉的代码:
Object activity = onRetainNonConfigurationInstance();
nci.activity = activity;
再回到getLastNonConfigurationInstance()方法中,
return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null;
由此我们知道onRetainNonConfigurationInstance()返回的是管理ViewModelStore的ComponentActivity.NonConfigurationInstance对象,接着看其实现:

@Override
    @Nullable
    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;
    }

onRetainNonConfigurationInstance()创建了一个持有ViewModelStroe的ComponentActivity.NonConfigurationInstance对象,到此我们追踪了一遍Activity销毁重新创建,而ViewModel保持不变的流程。总结下:
1、Activity销毁时,通过Activity.retainNonConfigurationInstances()创建Activity.NonConfigurationInstace对象交给ActivityClientRcord保存,而Activity.NoConfigurationInstance.activity持有ComponentActivity.NonConfigurationInstance对象,ComponentActivity.NonConfigurationInstance则持有了ViewModelStore
2、Activity创建后,在Activity.attch()中,将ActivityClientRcord持有的Activity.NonConfigurationInstace对象赋值给Activity.mLastNonConfigurationInstances
3、当调用ViewModelProviders.of()的时候,会调用ComponentActivity.getViewModelStore(),在getViewModelStore()中,会通过2的mLastNonConfigurationInstances获取到ComponentActivity.NonConfigurationInstance对象,并将ComponentActivity.NonConfigurationInstance持有的ViewModelStore返回。
这样就保证了Activity销毁重新创建,而ViewModelStore还是那个销毁前的ViewModelStore,所以我们通过
ViewModelProviders.of(target, factory).get(ViewModel.class)获取到的也还是Activity销毁前的那个ViewModel.

Fragment如何管理ViewModelStore

Fragment.getViewModelStore()实现如下:

public ViewModelStore getViewModelStore() {
       if (mFragmentManager == null) {
           throw new IllegalStateException("Can't access ViewModels from detached fragment");
       }
       return mFragmentManager.getViewModelStore(this);
   }

fragment自己并不直接管理ViewModel,通过代理FragmentManager.getViewModel()返回ViewModel,接下去再看FragmentManger.getViewModel的实现:FragmentManagerImpl.getViewModel()

ViewModelStore getViewModelStore(@NonNull Fragment f) {
        return mNonConfig.getViewModelStore(f);
    }

FragmentManagerImpl又通过mNonConfig去管理ViewModelStore,我们看看mNonConfig时在什么时候创建的:

public void attachController(@NonNull FragmentHostCallback host,
                                 @NonNull FragmentContainer container, @Nullable Fragment parent) {
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
        if (parent != null) {
            mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
        } else if (host instanceof ViewModelStoreOwner) {
            ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
            mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
        } else {
            mNonConfig = new FragmentManagerViewModel(false);
        }
    }

根据Fragment是否是子Fragment,以及Activity是否实现了ViewModelStoreOwner分为3中情况:
1、Fragment根Fragment且Activity实现了ViewModelStoreOwner接口时,从Activity.getViewModelStore获取viewModelStore,根据我们上面的分析可以知道这个viewModelStore是销毁重新创建前的viewModelStore,由于mNonConfig是个ViewModel,所以通过viewModelStore获取到的mNonConfig也是销毁重建前的mNonCofig。
2、fragment是子fragment时,mNonConfig从父Fragment的mNonConfig中获取,如果activity实现了ViewModelStoreOwner,则回到1,mNonCofig还是销毁前的那个mNonCofig;如果activity没有实现ViewModelStoreOwner,则回到3.
3.如果Activity没有实现ViewModelStoreOwner时,则从新创建一个全新的mNonConfig.
由于mNonConfig是销毁之前的mNonConfig,则通过mNonConfig管理的ViewModelStore也自然是销毁前的ViewModelStore。由此可见保证fragment的viewModeStore时销毁之前的ViewModelStore,是依赖于Activity的实现的。

相关文章

网友评论

      本文标题:ViewModel源码分析

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