内容简介:如果你想在多个注意:这里我使用了
ViewModel
是数据与 UI 分离的中间层,提供了一个将数据转换为 UI 友好型数据的场所。其次,它也提供了多 Fragment
复用相同 ViewModel
的机制。
简单使用
class UserViewModel(): ViewModel() { val userLiveData = LiveData<User>() override fun onCleared(){ // clear 工作,例如 Rxjava 里取消订阅 } } class UserFragment(): Fragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) val viewModel = ViewModelProviders.of(this).get(UserViewModel::class.java) viewModel.userLiveData.observe(viewLifecycleOwner, Observer { // update ui }) } }
如果你想在多个 Fragment
(同一个 Activity
)里复用这个 UserViewModel
, 那么只需要将 ViewModelProviders.of(this)
更换为 ViewModelProviders.of(activity)
即可, 这样 UserViewModel
的生存时间就会和 activity
一致。
注意:这里我使用了 viewLifecycleOwner
而没用使用 lifecycleOwner
。 而 viewLifecycleOwner
是在 androidx 中才存在,这主要是解决 Fragment
中 View
的生命周期与 Fragment
的生命周期不同步的问题。 假设从 FragmentA 跳转到 FragmentB 时, FragmentA 会经历下列生命周期:
onPause -> onStop -> onDestroyView
从 FragmentB 返回到 FragmentA 时, FragmentA 又会重新经历下列生命周期:
onCreateView -> onActivityCreated -> onStart -> onResume
如果用 Fragment
的生命周期 lifecycleOwner
, 那么将会在FragmentB 返回到 FragmentA 时产生新的 observe 订阅,而旧的订阅并没有被销毁。在之前的版本,可能需要开发者自己去处理重复订阅的问题,而新版 androidx 则提供了 View
的生命周期 viewLifecycleOwner
, 开发者可以视需求而采用不同的生命周期。
源码解析
ViewModel
并不是由用户直接通过构造器生成的,而是通过 ViewModelProvider
来获取,这使得使用者不用关心 ViewModel
的生命周期,全部交给框架内部解决。 框架提供了 ViewModelProviders
这个 工具 方法来提供各种场景下的 ViewModelProvider
// 提供一个将 viewModel 存储 在 Fragment 的 ViewModelProvider public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) { Application application = checkApplication(checkActivity(fragment)); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(fragment.getViewModelStore(), factory); } // 提供一个将 viewModel 存储 在 Activity 的 ViewModelProvider public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(activity.getViewModelStore(), factory); }
我们可以看出,其关键根据传参是 Fragment
还是 FragmentActivity
而提供不同的 ViewModelStore
:
-
如果是
Fragment
, 则ViewModelStore
依附在Fragment
上,它提供的ViewModel
可以存活至Fragment
销毁。 -
如果是
FragmentActivity
,则ViewModelStore
依附在FragmentActivity
上,它提供的ViewModel
可以存活至FragmentActivity
销毁。 因此这些ViewModel
可以在多个Fragment
中共享。
另外值得一提的是:只有 androidx 中的 Fragment
和 FragmentActivity
才实现了 ViewModelStoreOwner
接口。 所以 androidx 和这之前 support-v4 里的实现并不一样。 旧版本的实现也值得一提,这个我稍后再详细介绍。
public interface ViewModelStoreOwner { /** * Returns owned {@link ViewModelStore} * * @return a {@code ViewModelStore} */ @NonNull ViewModelStore getViewModelStore(); } // Fragment 关于 ViewModelStoreOwner 的实现 public class Fragment implements ViewModelStoreOwner, ... { // 省略其它源码... // ViewModelStore for storing ViewModels associated with this Fragment ViewModelStore mViewModelStore; public ViewModelStore getViewModelStore() { if (getContext() == null) { throw new IllegalStateException("Can't access ViewModels from detached fragment"); } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } return mViewModelStore; } public void onDestroy() { mCalled = true; FragmentActivity activity = getActivity(); boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations(); if (mViewModelStore != null && !isChangingConfigurations) { mViewModelStore.clear(); } } } // FragmentActivity 关于 ViewModelStoreOwner 的实现 public class FragmentActivity extends ComponentActivity implements ViewModelStoreOwner, ... { private ViewModelStore mViewModelStore; public ViewModelStore getViewModelStore() { if (getApplication() == null) { throw new IllegalStateException("Your activity is not yet attached to the " + "Application instance. You can't request ViewModel before onCreate call."); } if (mViewModelStore == null) { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null) { // Restore the ViewModelStore from NonConfigurationInstances mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } } return mViewModelStore; } protected void onCreate(@Nullable Bundle savedInstanceState) { //... NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null && nc.viewModelStore != null && mViewModelStore == null) { mViewModelStore = nc.viewModelStore; } // ... } protected void onDestroy() { super.onDestroy(); if (mViewModelStore != null && !isChangingConfigurations()) { mViewModelStore.clear(); } mFragments.dispatchDestroy(); } }
而 ViewModelStore
本身的实现比较容易,基本就是一个 HashMap
来保存 ViewModel
实例:
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); } /** * 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(); } }
ViewModelStore
的问题解决了,我们就可以看看 ViewModelProvider
是如何构造 ViewModel
实例并存入 ViewModelFactory
的了。首先看看 ViewModelProvider
里提供的 Factory
接口:
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); }
通过名字我们就可以看出,这是一个工厂模式的应用,我们可以通过实例出不同的 Factory 来以不同的方式构造 ViewModel
,当然,如果我们没有特殊需求,可以直接使用框架提供的默认 Factory 来构造无参数的 ViewModel
。 如果我们需要传参,则我们需要自己实现 Factory 接口了。
public class ViewModelProvider { private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"; private final Factory mFactory; private final ViewModelStore mViewModelStore; 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) { ViewModel viewModel = mViewModelStore.get(key); // 如果已经存在,则判断类型是否匹配 if (modelClass.isInstance(viewModel)) { //noinspection unchecked return (T) viewModel; } else { //noinspection StatementWithEmptyBody if (viewModel != null) { // TODO: log a warning. } } // 如果不存在,则通过 Factory 创建,并放入 mViewModelStore 中缓存 viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); //noinspection unchecked return (T) viewModel; } }
至此,整个 ViewModel
就说得差不多了,使用简单,原理也不是很难,但是功能确实强大。接下来会详细介绍下 ViewModel 1.x 版本时 ViewModelStore
的获取。那个时候, Fragment
和 FragmentActivity
还没有实现 ViewModelStoreOwner
。那我们又如何无感知的让生命周期融入框架中呢?
其实这里用了一个技巧,一个添加到 FragmentManager
的 Fragment
生命周期与 Activity
或者 parent fragment
的生命周期是一致的, 因此可以通过向 Activity
或者 Fragment
添加一个无 View
的 Fragment
来获取其生命周期,再将 ViewModelStore
依附在 这个 Fragment
上。 如果有看过 glide
源码的话,就可以发现其实它也是这么做的,非常成熟的套路,可以学习学习。
ViewModel 1.x 中 ViewModelStore 的获取
public static ViewModelProvider of(@NonNull Fragment fragment) { //... return new ViewModelProvider(ViewModelStores.of(fragment), sDefaultFactory); } public static ViewModelProvider of(@NonNull FragmentActivity activity) { //... return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory); }
我们可以看到,其主要其将核心逻辑抽取在了 ViewModelStores
中,接下来我以 FragmentActivity
为例继续追踪源码, Fragment
的逻辑大体相同,只是依赖于 childFragment
而已。
public static ViewModelStore of(@NonNull FragmentActivity activity) { return holderFragmentFor(activity).getViewModelStore(); } public static HolderFragment holderFragmentFor(FragmentActivity activity) { // 移交给 HolderFragmentManager 处理 return sHolderFragmentManager.holderFragmentFor(activity); } HolderFragment holderFragmentFor(FragmentActivity activity) { FragmentManager fm = activity.getSupportFragmentManager(); // 查找 FragmentManager 是否已经存在 HolderFragment HolderFragment holder = findHolderFragment(fm); if (holder != null) { // 已经存在,直接返回 return holder; } // 因为 fragment commit 是个异步的过程,所以 FragmentManager 不存在可能是因为 commit 还没执行完成,因此需要在 mNotCommittedActivityHolders 里也存放一份。 holder = mNotCommittedActivityHolders.get(activity); if (holder != null) { return holder; } if (!mActivityCallbacksIsAdded) { mActivityCallbacksIsAdded = true; // 添加 callback, 在 activity 销毁时移除 mNotCommittedActivityHolders 里的缓存, 一个应用只需添加一个 callback 足矣。 activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); } // 不存在,则创建,并存入 mNotCommittedActivityHolders 中 holder = createHolderFragment(fm); mNotCommittedActivityHolders.put(activity, holder); return holder; } private static HolderFragment createHolderFragment(FragmentManager fragmentManager) { HolderFragment holder = new HolderFragment(); // 添加 HOLDER_TAG, 便于寻找 fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss(); return holder; } private static HolderFragment findHolderFragment(FragmentManager manager) { //... // 通过 HOLDER_TAG 来寻找 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; }
这就是之前版本的做法,不过其实也可以通过 lifecycle 去做。有了 lifecycle 之后,这种做法就显得有些浪费了。但不管如何,这种对 Fragment 的应用也是值得称赞的。
以上所述就是小编给大家介绍的《Android 架构之美 - ViewModel》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 『互联网架构』软件架构-分布式架构(14)
- 『互联网架构』软件架构-电商系统架构(上)(69)
- 『互联网架构』软件架构-电商系统架构(中)(70)
- 『互联网架构』软件架构-电商系统架构(下)(71)
- 『互联网架构』软件架构-电商系统架构发展历程(68)
- 阿里P8架构师谈:淘宝技术架构从1.0到4.0的架构变迁!附架构资料
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
啊哈C语言!逻辑的挑战(修订版)
啊哈磊 / 电子工业出版社 / 2017-1 / 49
《啊哈C语言!逻辑的挑战(修订版)》是一本非常有趣的编程启蒙书,《啊哈C语言!逻辑的挑战(修订版)》从中小学生的角度来讲述,没有生涩的内容,取而代之的是生动活泼的漫画和风趣幽默的文字。配合超萌的编程软件,《啊哈C语言!逻辑的挑战(修订版)》从开始学习与计算机对话到自己独立制作一个游戏,由浅入深地讲述编程的思维。同时,与计算机展开的逻辑较量一定会让你觉得很有意思。你可以在茶余饭后阅读《啊哈C语言!逻......一起来看看 《啊哈C语言!逻辑的挑战(修订版)》 这本书的介绍吧!