Architecture Components源码分析之ViewModel
2017-12-26 10:28
363 查看
如果还不清楚什么是ViewModel,可以看下[译] Architecture Components 之 ViewModel 这个系列的文章,翻译自Android Developer的官方文章。
ViewModel 类是被设计用来存储和管理 UI 相关的数据,主要实现了两个功能:
1. 在配置更改(如:屏幕旋转)时数据可以保留下来。
2. 在 Fragment 之间共享数据。
接下来会通过分析源码的方式来看看是如何实现这两个功能的。
我们先来找到ViewModel这个类
发现只是一个抽象类,并且只有一个空实现的方法,说明实现特殊功能的代码一定在其他地方。
看过官方介绍的应该知道,ViewModel是通过ViewModelProvider创建的:
那我们从这里开始分析,通过调用
ViewModelProvider类中将构造的参数ViewModelStore和Factory作为成员变量,
既然有一个
接下的问题便是:
这个很简单,也很好理解,仅仅是一个HashMap用于存放ViewModel,提供放入,获取,清空的方法。
我们回到
注意到通过静态引入的方法调用了
这个类就是ViewModel的核心类了,所有的功能都是通过该类来实现的,注意看好啦~
我们找到了
就是这个方法保证了activity因配置更改重建时,该fragment的实例不会销毁,重建后的Activity还是使用该实例。
创建HolderFragment 的过程还有很多细节。
需要注意的是
这段代码是通过Application的registerActivityLifecycleCallbacks注册一个全局Activity生命周期的回调,任何Activity触发了生命周期都会在mActivityCallbacks中回调对应的方法。
一开始我以为
上面
DefaultFactory可以创建
如果你的ViewModel实例的创建需要其他参数,则要自己实现Factory复写create。
关于第二条功能:在 Fragment 之间共享数据也很好理解了,在同一个Activity的不同Fragment种使用
ViewModel 类是被设计用来存储和管理 UI 相关的数据,主要实现了两个功能:
1. 在配置更改(如:屏幕旋转)时数据可以保留下来。
2. 在 Fragment 之间共享数据。
接下来会通过分析源码的方式来看看是如何实现这两个功能的。
我们先来找到ViewModel这个类
ViewModel
public abstract class ViewModel { /** * This method will be called when this ViewModel is no longer used and will be destroyed. * <p> * It is useful when ViewModel observes some data and you need to clear this subscription to * prevent a leak of this ViewModel. */ @SuppressWarnings("WeakerAccess") protected void onCleared() { } }
发现只是一个抽象类,并且只有一个空实现的方法,说明实现特殊功能的代码一定在其他地方。
看过官方介绍的应该知道,ViewModel是通过ViewModelProvider创建的:
public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class); model.getUsers().observe(this, users -> { // 更新 UI }); } }
那我们从这里开始分析,通过调用
ViewModelProviders.of(this).get(MyViewModel.class)是如何获取到ViewModel的那?我们来看
ViewModelProviders的
of()方法(of方法重载还有Fragment,这里我们只分析Activity,Fragment与activity如出一辙):
@MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity) { initializeFactoryIfNeeded(checkApplication(activity)); return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory); } @SuppressLint("StaticFieldLeak") private static DefaultFactory sDefaultFactory; private static void initializeFactoryIfNeeded(Application application) { if (sDefaultFactory == null) { sDefaultFactory = new DefaultFactory(application); } } 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; }
ViewModelProviders.of()方法返回了一个ViewModelProvider对象,该对象需要两个参数:ViewModelStore、Factory。通过命名,我们可以猜测ViewModelStore是一个ViewModel的仓库,用于缓存ViewModel,Factory是工厂类,用于创建ViewModel实例。获取到ViewModelProvider对象后,又调用了它的
get方法就获取到ViewModel对象,来看下这个方法:
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; }
ViewModelProvider类中将构造的参数ViewModelStore和Factory作为成员变量,
get方法先是从
mViewModelStore.get中获取,如果没有获取到则通过
Factory创建一个
ViewModel实例,并放入
ViewModelStore中,这种使用方式更加验证了上面我们的猜测,之后会仔细分析
ViewModelStore以及
Factory。
既然有一个
ViewModel的缓存
ViewModelStore,那第一个功能:在配置更改(如:屏幕旋转)时数据可以保留下来,就很好理解了。只要让缓存在Activity配置更改重建是存活下来,那重建后获取的
ViewModel就是之前缓存的那个了。
接下的问题便是:
ViewModelStore存放在哪里可以保证在Activity配置更改重建是存活下来?
ViewModelStore
字面意思即为ViewModel的仓库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(); } }
这个很简单,也很好理解,仅仅是一个HashMap用于存放ViewModel,提供放入,获取,清空的方法。
我们回到
ViewModelProviders.of()方法来,这里是通过
ViewModelStores.of(activity)获取到的ViewModelStore对象的,我们继续进入这个方法:
import static android.arch.lifecycle.HolderFragment.holderFragmentFor; public class ViewModelStores { private ViewModelStores() { } public static ViewModelStore of(@NonNull FragmentActivity activity) { return holderFragmentFor(activity).getViewModelStore(); } }
注意到通过静态引入的方法调用了
HolderFragment的
holderFragmentFor ()方法,接着找到
HolderFragment:
HolderFragment
public class HolderFragment extends Fragment { ...//去除了framgent相关的代码,只保留activity相关 private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager(); public static final String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderHolderFragment"; private ViewModelStore mViewModelStore = new ViewModelStore(); 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(); } public ViewModelStore getViewModelStore() { return mViewModelStore; } public static HolderFragment holderFragmentFor(FragmentActivity activity) { return sHolderFragmentManager.holderFragmentFor(activity); } static class HolderFragmentManager { private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>(); private ActivityLifecycleCallbacks mActivityCallbacks = new EmptyActivityLifecycleCallbacks() { @Override public void onActivityDestroyed(Activity activity) { HolderFragment fragment = mNotCommittedActivityHolders.remove(activity); if (fragment != null) { Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity); } } }; private boolean mActivityCallbacksIsAdded = false; void holderFragmentCreated(Fragment holderFragment) { Fragment parentFragment = holderFragment.getParentFragment(); if (parentFragment != null) { mNotCommittedFragmentHolders.remove(parentFragment); parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks( mParentDestroyedCallback); } else { mNotCommittedActivityHolders.remove(holderFragment.getActivity()); } } 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; } 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; } }
这个类就是ViewModel的核心类了,所有的功能都是通过该类来实现的,注意看好啦~
HolderFragment.holderFragment()方法直接返回了
sHolderFragmentManager.holderFragmentFor(activity)的结果。而
HolderFragmentManager的
holderFragmentFor方法实际上就是创建了一个HolderFragment的实例,并添加到参数activity中,为了避免重复添加,先是调用
findHolderFragment(fm)看看能否找到已添加HolderFragment,如果没有的话再从缓存的Map中找,还是没有话才去创建一个新的实例,放入缓存的Map,并返回这个对象,继而调用
getViewModelStore()获取
viewModelStore实例。
我们找到了
ViewModelStore存放位置,是在HolderFragment中,那它如何保证在Activity配置更改重建是存活下来的?其实关键代码就是Fragment的一个方法:
/** * Control whether a fragment instance is retained across Activity * re-creation (such as from a configuration change). This can only * be used with fragments not in the back stack. If set, the fragment * lifecycle will be slightly different when an activity is recreated: * <ul> * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still * will be, because the fragment is being detached from its current activity). * <li> {@link #onCreate(Bundle)} will not be called since the fragment * is not being re-created. * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b> * still be called. * </ul> */ setRetainInstance(true);
就是这个方法保证了activity因配置更改重建时,该fragment的实例不会销毁,重建后的Activity还是使用该实例。
创建HolderFragment 的过程还有很多细节。
需要注意的是
HolderFragmentManager是声明在
HolderFragment中的static成员,因此会随着
HolderFragment的首次加载创建实例,只存在一个实例并永远在内存中,缓存的map是
HolderFragmentManager的成员变量,也会永远在内存中,而
HolderFragment可以创建多个实例,所以对于不再需要的
HolderFragment实例,需要及时从map中移除。
if (!mActivityCallbacksIsAdded) { mActivityCallbacksIsAdded = true; activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); }
这段代码是通过Application的registerActivityLifecycleCallbacks注册一个全局Activity生命周期的回调,任何Activity触发了生命周期都会在mActivityCallbacks中回调对应的方法。
HolderFragment的源码中就是通过该回调,在绑定
HolderFragment的Activity触发onDestroy方法后移除map中的缓存。
一开始我以为
HolderFragmentManager会缓存
HolderFragment直到依附的activity销毁才会移除缓存,但后来注意到在
HolderFragment的
onCreate方法中调用了
sHolderFragmentManager.holderFragmentCreated(this);直接移除了缓存。因此,这个缓存仅仅是从
HolderFragment的add方法调用到
onCreate方法执行为止。或者add了Fragment但是还没有添加到Activity执行onCreate方法,依附的Activity就销毁了,也会回调mActivityCallbacks的onDestroy方法移除HolderFragment的缓存。我想了很久也没有想到这个缓存的使用场景,好像这个缓存是没有意义的。
Factory
即为创建ViewModel的工厂类,是一个接口,我们可以实现这个接口定义自己的ViewModel工厂。/** * Implementations of {@code Factory} interface are responsible to instantiate ViewModels. */ public interface Factory { /** * Creates a new instance of the given {@code Class}. * <p> * * @param modelClass a {@code Class} whose instance is requested * @param <T> The type parameter for the ViewModel. * @return a newly created ViewModel */ @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass); }
上面
of()使用的
sDefaultFactory默认工厂:
public static class DefaultFactory extends ViewModelProvider.NewInstanceFactory { private Application mApplication; /** * Creates a {@code DefaultFactory} * * @param application an application to pass in {@link AndroidViewModel} */ public DefaultFactory(@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); } } public static class NewInstanceFactory implements Factory { @NonNull @Override 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); } } }
DefaultFactory可以创建
AndroidViewModel的对象,调用它
AndroidViewModel(@NonNull Application application)构造创建实例,如果不是AndroidViewModel.class则调用父类NewInstanceFactory的create方法调用ViewModel无参数的构造。
如果你的ViewModel实例的创建需要其他参数,则要自己实现Factory复写create。
总结
ViewModelProviders.of()提供
ViewModelProvider,
ViewModelProvider通过
ViewModelStore和
Factory管理和创建ViewModel,
ViewModelStore的引用存储在向目标Activity/Fragment中添加的无界面
HolderFragment中,并通过
setRetainInstance(true);以保证在Activity配置更改重建是存活下来。
关于第二条功能:在 Fragment 之间共享数据也很好理解了,在同一个Activity的不同Fragment种使用
ViewModelProviders.of()时,参数需要传入Activity对象,第一次获取ViewModel时会创建一个新对象,而另一个Fragment获取相同ViewModel时,则会从
ViewModelStore的缓存中获取,两个Fragment持有的时同一个ViewModel对象,就能实现Fragment之间通讯了。但是这种通讯的前途是必须在同一个Activity中。
相关文章推荐
- Django Rest Framework----ModelViewSet视图 ModelViewSet源码分析
- MVVMLight源码分析之消息机制和ViewModelBase
- [置顶] Android Architecture Component之ViewModel源码分析
- View编程:invalidate()源码分析
- Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)
- 源码带你分析View的工作原理
- yii分析 yii的 view语法和model中的relations
- xUtils3源码分析(一):view的绑定
- mvc源码解读(4)-ViewData&ViewBag&TempData&ViewModel
- 【Android开源项目分析】自定义圆形头像CircleImageView的使用和源码分析
- Robotium中webview源码分析
- ViewPager实现源码分析
- ModelAndView与ModelMap的源码
- Android View系统源码分析(九)—— ViewRoot.ensureTouchMode()
- Android触摸屏事件派发机制详解与源码分析一(View篇)
- 自定义控件View之onMeasure调用时机源码分析
- Android布局优化之ViewStub、include、merge使用与源码分析
- 从Android源码分析View绘制
- Android webView与js 交互以及jsbridge框架源码分析
- Android触摸屏事件派发机制详解与源码分析一(View篇)