Android知识Android技术知识Android开发经验谈

Android Architecture Component之V

2017-11-14  本文已影响0人  Jason骑蜗牛看世界
前言
知识准备
ViewModel是什么?
用法简介
ViewModel的生命周期
image

从图中可以看出我们发现,当activity因屏幕旋转而销毁,但是ViewModel一直存在,也就是这个对象一直都在(框架核心,怎么实现源码分析会讲到),直到finished才调用clear清除内存。

Fragment之间共享数据

源码分析
  1. 我们先找到程序的入口
    ViewModelProviders.of(this).get(MyViewModel.class)
    
    1. 先看of方法

       return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory)
      

      返回一个ViewModelProvider,需要两个参数ViewModelStore(存放ViewModel的仓库),Factory(用工厂模式创建我们的ViewModel对象)。假如说我们的Activity重新绘制了,那么这里的ViewModelProvider就是不同的实例。这个类主要的作用就是获取我们ViewModel对象。

    2. 看一下of()方法

      ViewModelStores.of(activity)
      

      ViewModelStores是干什么的呢?提供一些静态方法获取所传入activity的ViewModeStore.

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

      @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
      public static HolderFragment holderFragmentFor(FragmentActivity activity) {
          return sHolderFragmentManager.holderFragmentFor(activity);
      }
      
      • 我们看到是静态方法,这个方法不是ViewModelStore,而是
        HolderFragment的一个静态方法,返回一个HolderFragment对象.
      • 然后回到3处调用getViewModelStore,返回ViewModelStore。所以说HolderFragment中有一个ViewModelStore。对应关系是一个HolderFrament含有一个ViewModelStore(存放ViewModel的仓库),一个ViewModelStore存放着多个ViewModel。
      • HolderFragmentManager是属于HolderFramgent的静态内部类
    4. 在(iii)处调用了sHolderFragmentManager.holderFragmentFor

       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;
                      }
              holder = createHolderFragment(fm);
              mNotCommittedActivityHolders.put(activity, holder);
              return holder;
          }
      
      • 首先在在Activity的supportFragmentManager中的查找,有的话就会返回

                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;
        }
        
      • 没有的话在我们存放的集合中查找有的话就返回,在HolderFragmentManager集合如下

         private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
        

        可以看出多个Activity可能对应一个HolderFrament

      • 没有的话就创建并放入我们的mNotCommittedActivityHolders。

        private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
                HolderFragment holder = new HolderFragment();
                fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
                return holder;
            }
        

        创建Fragment对象,这是一个无ui的Fragment,==主要作用就是用ViewModelStore储存我们的ViewModel,并在Fragement的OnDestory调用ViewModelStore的clear释放所有内存==。

        有人要说,fragment对象还是要重建啊,那么ViewModel也要重建啊,因为它属于Fragment,这就用到了文章开篇讲到了setRetainInstance方法。看下源码

        public HolderFragment() {
             setRetainInstance(true);
        }
        

        在我们初始化的时候会调用setRetainInstance,这就解决这个问题了。

    5. 拿到HolderFragment对象,回到(ii)处调用getViewModelStore,拿到ViewModelStore对象。

  2. 我们拿到ViweModelStore回到(1)处,我们就去拿我们的ViewModel。看源码
    @NonNull
    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);
    }
    
    • 看get(DEFAULT_KEY + ":" + canonicalName, modelClass)
        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;
    }
    
    • 首先是我们从mViewModelStore取出我们想要的ViewModel.
      有的话就返回
    • 没有的话就利用工厂模式反射生产我们所要的ViewModel对象,同时把我们的ViewModel对象放入mViewModelStore。同时返回我们的ViewModel.

总结:

核心思想就是HolderFragment调用setsetRetainInstance(true),使得HolderFragment在FragmentMannager调用FindFragmentBytag,找到的是同一个HolderFragment对象(无论Activity是否重绘),这也保证了HolderFragment中的ViewModelStore(存放我们ViewModel的地方)不被销毁,然后我们取出我们所要的ViewModel,进行数据读取。

参考

官方文档

上一篇下一篇

猜你喜欢

热点阅读