ViewModel 源码解析

MVVM架构中,会用到ViewModel类,那么这个类原理是什么呢?有什么好处呢?

第一部分:源码文档解析

/**
 * ViewModel is a class that is responsible for preparing and managing the data for
 * an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.
    //viewmodel类是用来在activity或fragment中获取和处理数据的类
 * It also handles the communication of the Activity / Fragment with the rest of the application
   //他也可以用来处理activity或fragment和应用其他模块的通信
 * (e.g. calling the business logic classes).
 * <p>
 * A ViewModel is always created in association with a scope (a fragment or an activity) and will
 * be retained as long as the scope is alive. E.g. if it is an Activity, until it is
 * finished.
 * <p>
    //viewmodel随着宿主的创建而创建,而且只要宿主还在他就会活着
 * In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a
 * configuration change (e.g. rotation). The new owner instance just re-connects to the existing model.
 * <p>
    //也就是说,这也就是如果宿主死了他不会跟着死的,例如activity的配置更改后重新创建,但是他还是原来的。
 * The purpose of the ViewModel is to acquire and keep the information that is necessary for an
 * Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the
 * ViewModel. ViewModels usually expose this information via {@link LiveData} or Android Data
 * Binding. You can also use any observability construct from you favorite framework.
 * <p>
    //设计viewmodel的目的是获得和保持activity或fragment中的信息。宿主fragment/activity也应该观察viewmodel中数据的改变。viewmodel通常配合着databinding使用,你也可以使用其他具有观察特性的控件一起使用。
 * ViewModel's only responsibility is to manage the data for the UI. It <b>should never</b> access
 * your view hierarchy or hold a reference back to the Activity or the Fragment.
 * <p>
  //viewmodel仅仅用来管理更新UI的数据,而不应该持有view或者宿主的引用。
 * Typical usage from an Activity standpoint would be:
 * <pre>
    //使用示例如下:
 * public class UserActivity extends Activity {
 *
 *     {@literal @}Override
 *     protected void onCreate(Bundle savedInstanceState) {
 *         super.onCreate(savedInstanceState);
 *         setContentView(R.layout.user_activity_layout);
 *         final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
 *         viewModel.getUser().observe(this, new Observer&lt;User&gt;() {
 *             {@literal @}Override
 *             public void onChanged(@Nullable User data) {
 *                 // update ui.
 *             }
 *         });
 *         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
 *             {@literal @}Override
 *             public void onClick(View v) {
 *                  viewModel.doAction();
 *             }
 *         });
 *     }
 * }
 * </pre>
 *
 * ViewModel would be:
 * <pre>
 * public class UserModel extends ViewModel {
 *     private final MutableLiveData&lt;User&gt; userLiveData = new MutableLiveData&lt;&gt;();
 *
 *     public LiveData&lt;User&gt; getUser() {
 *         return userLiveData;
 *     }
 *
 *     public UserModel() {
 *         // trigger user load.
 *     }
 *
 *     void doAction() {
 *         // depending on the action, do necessary business logic calls and update the
 *         // userLiveData.
 *     }
 * }
 * </pre>
 *
 * <p>
 * ViewModels can also be used as a communication layer between different Fragments of an Activity.
  //viewmodel也可以用来用在同一个activity中不同fragment之间数据交换
 * Each Fragment can acquire the ViewModel using the same key via their Activity. This allows
 * communication between Fragments in a de-coupled fashion such that they never need to talk to
 * the other Fragment directly.
 * <pre>
  //每一个fragment可以通过同一个key获取到同一个viewmodel,这就实现了fragment之间的数据交换,而不是fragment之间进行数据交换。例如:
 * public class MyFragment extends Fragment {
 *     public void onStart() {
 *         UserModel userModel = new ViewModelProvider(requireActivity()).get(UserModel.class);
 *     }
 * }
 * </pre>
 * </>
 */

通过官方文档我可以获取如下信息:

1.viewmodel的生命周期不随着宿主的死亡而死亡

2.viewmodel 主要是用来进行数据的传递更新UI,而不允许持有宿主的引用

3.viewmodel 应该配合着具有观察者模式的类一起使用,例如MutableLiveData

4.使用示例

5.viewmodel还可以作为同一个activity中不同fragment之间数据的传递,以及示例

第二部分:源码解析(上面示例用代码)

1.获取viewmodel 

UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
/**
     * Creates {@code ViewModelProvider}. This will create {@code ViewModels}
     * and retain them in a store of the given {@code ViewModelStoreOwner}.
     * <p>
     * This method will use the
     * {@link HasDefaultViewModelProviderFactory#getDefaultViewModelProviderFactory() default factory}
     * if the owner implements {@link HasDefaultViewModelProviderFactory}. Otherwise, a
     * {@link NewInstanceFactory} will be used.
     */
    //参数二有删减,默认就是这个参数
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), NewInstanceFactory.getInstance());
    }

先看new ViewModelProvider(this):

参数为this(例如activity /fragment),那么是任何类都可以吗?不是,这个构造器的参数为ViewModelStoreOwner,这是个接口

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

我们看看他的子类有哪些:

 所以我们传入fragmentactivity可以,也就是如果不是这几个类,那么我们要实现这个接口才可以,我们可以看看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();
    }
}

核心代码,hashmap保存viewmodel的。

第二个参数NewInstanceFactory.getInstance()

public static class NewInstanceFactory implements Factory {

        private static NewInstanceFactory sInstance;

        
        @NonNull
        static NewInstanceFactory getInstance() {
            if (sInstance == null) {
                sInstance = new NewInstanceFactory();
            }
            return sInstance;
        }

        @SuppressWarnings("ClassNewInstance")
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            return modelClass.newInstance();
        }
    }

单例模式,就一个create方法,反射创建对象。

再次回顾一下两个重要点:

第一:一个hashmap保存viewmodel

第二:一个是创建viewmodel的

下面来看new ViewModelProvider(this).get(UserModel.class); get方法:

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        //获取全类名
        String canonicalName = modelClass.getCanonicalName();
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        //hashmap中获取
        ViewModel viewModel = mViewModelStore.get(key);
        //获取到了,说明以前创建过,则返回
        if (modelClass.isInstance(viewModel)) {
            return (T) viewModel;
        } 
        //没获取到,则创建,通过上面分析的反射创建
        viewModel = mFactory.create(modelClass);
       //将创建的对象保存起来
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

通过全类名在hashmap中查找,如果有则直接返回,没有则创建新的,并保存起来。所以说,我们多次调用get方法获取或者在同一个activity中不同fragment中使用new ViewModelProvider(getActivity()).get(UserModel.class) 都是获取到的同一个viewmodel。但是文档里说当activity的配置信息发生改变,activity重新创建的时候,viewmodel是不会重新创建的,可是我们看到的却是 mViewModelStore 是activity的一个属性,也就是说activity销毁的时候,他也应该被回收了,那应该随着新的activity的创建而创建新的viewmodel吧,文档写的貌似不对啊?其实文档写的没错,我们可以去activity里看看:

//activity配置发生改变是调用这个方法
public final Object onRetainNonConfigurationInstance() {
       
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

我们可以看到,当activity配置发生改变时,会将viewModelStore保存起来,当页面重新创建后再次获取实例时,会调用:

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        ensureViewModelStore();
        return mViewModelStore;
    }

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    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();
            }
        }
    }

会先在配置改变保存的数据里恢复数据,没有则再去创建。

后续viewmodel配合LiveData一起使用,我们后续再分析。这里就分析viewmodel的源码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值