jetPack-ViewModel 原理分析

现在viewmodel的实现在androidX前后有两个版本,实现方式有着不小的差异

AndroidX前 viewmodel

使用方法
ViewModelProviders.of(activity/fragment).get(MyViewModel::class.java)
ViewModelProviders
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
            factory = AndroidViewModelFactory.getInstance(application);
        }

        return new ViewModelProvider(ViewModelStores.of(fragment), (Factory)factory);
    }

这个方法是为了获取ViewModelProvider,获取它的参数之一为ViewModelStores.of(activity/fragment)

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

    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        return fragment instanceof ViewModelStoreOwner ? ((ViewModelStoreOwner)fragment).getViewModelStore() : HolderFragment.holderFragmentFor(fragment).getViewModelStore();
    }
ViewModelStore
public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap();

    public ViewModelStore() {
    }

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

    }

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

    public final void clear() {
        Iterator var1 = this.mMap.values().iterator();

        while(var1.hasNext()) {
            ViewModel vm = (ViewModel)var1.next();
            vm.onCleared();
        }

        this.mMap.clear();
    }
}

viewModel 就是存储在ViweModelStore中的

获取viewmodelStore:如果activity/fragment实现了ViewModelStoreOwner那就是它们自己管理了ViewModelStore
,如果没有实现就会创建一个HolerFragment来管理viewmodelStore

HolderFragment
HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            } else {
                holder = (HolderFragment)this.mNotCommittedActivityHolders.get(activity);
                if (holder != null) {
                    return holder;
                } else {
                    if (!this.mActivityCallbacksIsAdded) {
                        this.mActivityCallbacksIsAdded = true;
                        activity.getApplication().registerActivityLifecycleCallbacks(this.mActivityCallbacks);
                    }

                    holder = createHolderFragment(fm);
                    this.mNotCommittedActivityHolders.put(activity, holder);
                    return holder;
                }
            }
        }

        HolderFragment holderFragmentFor(Fragment parentFragment) {
            FragmentManager fm = parentFragment.getChildFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            } else {
                holder = (HolderFragment)this.mNotCommittedFragmentHolders.get(parentFragment);
                if (holder != null) {
                    return holder;
                } else {
                    parentFragment.getFragmentManager().registerFragmentLifecycleCallbacks(this.mParentDestroyedCallback, false);
                    holder = createHolderFragment(fm);
                    this.mNotCommittedFragmentHolders.put(parentFragment, holder);
                    return holder;
                }
            }
        }

这两个方法就是为了获取或者创建HolderFragment

public HolderFragment() {
        this.setRetainInstance(true);
    }

添加 setRetainInstance 为 true 那么在activity销毁重建是 fragment 不会走destory方法。里面的viewModelstore就保存下来了。

AndroidX 之后

使用方法
val viewModel = ViewModelProvider(this).get(DemoViewModel::class.java)

现在已经没有HolderFragment 了,ComponentActivity 和 Framgnet 已经自己实现了viewModelStoreOwner
, 但是viewmodelStore的代码并没有任何变化。所以只要看viewmodelstore如何保存的就行了。

找到getViewModelStore -> ensureViewModelStore

void ensureViewModelStore() {
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
    }

这里是确保viewmodelstore不为null,那肯定之前就有为viewmodelstore赋值的地方了。

onRetainNonConfigurationInstance()
public final Object onRetainNonConfigurationInstance() {
        // Maintain backward compatibility.
        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;
         // 把viewModelStore放到NonConfigurationInstances中并返回,这样当页面被重建而销毁时ViewModelStore就被保存起来了

        nci.viewModelStore = viewModelStore;
        return nci;
    }

在Activity启动流程中,当ActivityThread执行performDestroyActivity这个方法时,会调用Activity的retainNonConfigurationInstances()方法获取到保存的数据并保存到ActivityClientRecord中。

//Activity中的retainNonConfigurationInstances()方法
NonConfigurationInstances retainNonConfigurationInstances() {
        //ComponentActivity中的onRetainNonConfigurationInstance()方法
        Object activity = onRetainNonConfigurationInstance();
        ···
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = activity;
        ···
        return nci;
    }

ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {
   ...
   //保存retainNonConfigurationInstances中的数据到ActivityClientRecord中
   ActivityClientRecord r = mActivities.get(token);
   r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
   ...
   return r;

当页面重建完成,ActivityThread执行了performLaunchActivity方法时,会调用Activity的attach方法,便会把刚刚存储的数据,传递进去。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //传递之前储存的数据
    activity.attach(......, r.lastNonConfigurationInstances,.....);
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值