美文网首页
ViewModel源码分析

ViewModel源码分析

作者: 24k金 | 来源:发表于2019-03-13 17:13 被阅读0次

    一、ViewModel的简介

    2018年谷歌IO大会上正式发布了JetPack组件,其中包括Databing、Lifecycles、LiveData、Navigation、Paging、Room、ViewModel、WorkManager等一系列框架。并且发布androidx包,这些框架的最新版本组件将引入到androidx包下。
    JetPack架构组件的发布,意味着google终于拿出了官方推荐的Android开发架构,一直以来在Android开发上老生常谈三种开发模式,MVC、MVP、MVVM。整体的思想就是做一些代码封装和操作上的分离,具体三种架构的区别不在这详细描述。说一点儿个人对这三中开发模式的理解。
    MVC:Activity承担C的任务,强行carry大量业务和数据代码。
    MVP:Presenter承担主要代码任务,连接数据层和视图层的交互。
    MVVM:Model负责数据、View负责展示、ViewModel负责Model和View的交互,同时,最好的一点是View层自动监听ViewModel的数据变化。
    在JetPack组件出现之前,一直以来构建MVVM架构的方式都是代用Databing来充当ViewModel,而Databing是采用标签方式写入布局文件中的,这样一来当出现问题的时候不是太好进行调试。所以ViewMode的出现对于MVVM模式开发具有重大的意义。

    二、ViewModel的用法和特点
    ViewModel的使用是要结合LiveData框架进行的,LiveData框架也是JetPack组件的一部分,这里先不详细进行介绍。ViewModel有两个特点,一是更加方便的保存数据,第二个特点,也是最重要的特点,就是保证数据不受Activity的销毁重建所影响,当Activity销毁重建后仍然能收到之前的数据。

    1)继承ViewModel

     class MainViewModel : ViewModel() {
        private val repertory: MainRepository by lazy { MainRepository() }
        var data: MutableLiveData<JsonBean> = MutableLiveData()
        fun getDataFromServer(){
        repertory.getDataFromServer(data)
         }
        }
    

    ViewModel中持有LiveData,LiveData是ViewModel持有数据的载体。

    2)Activity通过ViewModelProviders获取ViewModel

    class MainActivity : AppCompatActivity() {
    private lateinit var mModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initData()
    }
    
    private fun initData() {
        mModel = ViewModelProviders.of(this)[MainViewModel::class.java]
        mModel.data?.observe(this, Observer {
            val mainAdapter = MainAdapter(this, it)
            val linearLayoutManager = LinearLayoutManager(this)
            rv.layoutManager = linearLayoutManager
            rv.adapter = mainAdapter
        })
        mModel.getDataFromServer()
     }  
    }
    

    3)通过ViewModel中的方法获取数据然后改变LiveData状态,通过响应式的方式通知到Activity进行视图更新。用法上比较简单。

    三、源码分析

    个人认为对于一个框架的学习仅仅掌握框架的用法是不够的,因为这太简单了,曾经看到过一篇博客,里面有一句话说的很好,”如果你只会用这个框架,而不清楚其中的原理和设计,那么即便这个框架性能再好,再牛逼,那也是写框架的那个人牛逼,而不是你牛逼“。我认为这句话说的很好,所以当我们学习一中新框架的时候,不能单单只会用,一定要清楚其中的原理,尽量去理解作者的设计思想,就像品茶一样,这样才能品出里面的滋味。不扯闲篇了,由于作者能力也有限,所以以上和以下分析,如有不同观点或作者描述有误请给予批评指正,欢迎来喷。

    1)先从获取ViewModel的类入手,”ViewModelProviders“从类名中也能分析出这个类是用于提供ViewModel的。源码如下:

    public class ViewModelProviders {
    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;
    }
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment) {
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(checkActivity(fragment)));
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(activity));
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
        checkApplication(checkActivity(fragment));
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @NonNull Factory factory) {
        checkApplication(activity);
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
    @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);
        }
    }
    }
    

    我们从中可以看到,这个类中的方法全是静态的,说明这个类相当于一个工具类,从of方法中我们可以看到真正实现ViewModel创建的类是ViewModelProvider,而这个类的构建又需要通过ViewModelStores的of方法获取,ViewModelStores的代码如下:

    public class ViewModelStores {
    private ViewModelStores() {
    }
    
    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }
    
    @NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }
    }
    

    从这个类中可以发现获取ViewModelStore是通过构建一个HoldFragment,而这个HoldFragment的作用就是持有ViewModelStore的引用,然后将这个Fragment添加到Activity中,而且这个Fragmet有一个重要的特点,在实例化的时候会调用setRetainInstance(true)方法,这个方法的作用是让Fragment不受Activity销毁重建影响,这样一来就能保证ViewModel不会由于Activity的销毁重建导致数据丢失,这是ViewModel的一个重要特性。这种设计确实很巧妙,HolderFragment的代码如下:

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public class HolderFragment extends Fragment implements ViewModelStoreOwner {
    .......省略部分代码
    
    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) {
        return sHolderFragmentManager.holderFragmentFor(activity);
    }
    
    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }
    .....省略部分代码
        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);
            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;
        }
    }
    

    之后来到ViewModelProvider,代码量不是很多,但是里面的设计确实很有意思。首先来分析它的成员变量,成员变量只有两个,Factory从字面的意思就能理解,它是生产ViewModel的工厂,所以这里用到了工厂模式。ViewModelStore它用来存储ViewModel,相当于ViewModel的缓存。内部是一个HashMap,key是ViewModel的类名称。ViewModelProvider代码如下:

    public class ViewModelProvider {
    ....省略部分代码
    private final Factory mFactory;
    private final ViewModelStore mViewModelStore;
    
    ......
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }
    
    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }
    
    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);
    }
    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;
        .......省略部分代码
    }
    

    2)Factory是ViewModelProvider中的一个接口,定义如下:

    public interface Factory {
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }
    

    通过create方法创建ViewModel。Factory有两个实现类AndroidViewModelFactory、NewInstanceFactory都是ViewModelProvider中的静态内部类。同时AndroidViewModelFactory又继承于NewInstanceFactory。有一种依赖注入的思想在里面。接下来我们来分析两个Factory的实现类。NewInstanceFactory最终通过newinstance方法创建ViewModel实例。

    public static class NewInstanceFactory implements Factory {
        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);
            }
        }
    }
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    
        private static AndroidViewModelFactory sInstance;
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }
        private Application mApplication;
    
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }
    
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> 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);
        }
    }
    

    最后,真正存储ViewModel的容器是ViewModelStore,ViewModelStore中维护了一个HashMap,代码如下:

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

    }

    文章代码库:https://github.com/24KWYL/MVVM.git

    相关文章

      网友评论

          本文标题:ViewModel源码分析

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