Android架构组件JetPack之ViewModel(二)

});
}
}

如果Activity被重新创建了,它会收到被之前Activity创建的相同MyViewModel实例。当所属Activity终止后,框架调用ViewModel的onCleared()方法清除资源。

因为ViewModel在指定的Activity或Fragment实例外存活,它应该永远不能引用一个View,或持有任何包含Activity context引用的类。如果ViewModel需要Application的context(如获取系统服务),可以扩展AndroidViewmodel,并拥有一个构造器接收Application。

在Fragment间共享数据

一个Activity中的多个Fragment相互通讯是很常见的。之前每个Fragment需要定义接口描述,所属Activity将二者捆绑在一起。此外,每个Fragment必须处理其他Fragment未创建或不可见的情况。通过使用ViewModel可以解决这个痛点,这些Fragment可以使用它们的Activity共享ViewModel来处理通讯:

public class SharedViewModel extends ViewModel {
private final MutableLiveData selected = new MutableLiveData();

public void select(Item item) {
selected.setValue(item);
}

public LiveData getSelected() {
return selected;
}
}

public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}

public class DetailFragment extends LifecycleFragment {
public void onActivityCreated() {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}

注意:上面两个Fragment都用到了如下代码来获取ViewModel,getActivity()返回的是同一个宿主Activity,因此两个Fragment之间返回的是同一个SharedViewModel对象。

SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

这种方式的好处包括:

1.Activity不需要做任何事情,也不需要知道通讯的事情
2.Fragment不需要知道彼此,除了SharedViewModel进行联系。如果它们(Fragment)其中一个消失了,其余的仍然能够像往常一样工作。
3.每个Fragment有自己的生命周期,而且不会受其它Fragment生命周期的影响。事实上,一个Fragment替换另一个Fragment,UI的工作也不会受到任何影响。

ViewModel的生命周期

ViewModel对象的范围由获取ViewModel时传递至ViewModelProvider的Lifecycle所决定。ViewModel始终处在内存中,直到Lifecycle永久地离开—对于Activity来说,是当它终止(finish)的时候,对于Fragment来说,是当它分离(detached)的时候。

上图左侧为Activity的生命周期过程,期间有一个旋转屏幕的操作;右侧则为ViewModel的生命周期过程。

一般通过如下代码初始化ViewModel:

viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);

this参数一般为Activity或Fragment,因此ViewModelProvider可以获取组件的生命周期。

Activity在生命周期中可能会触发多次onCreate(),而ViewModel则只会在第一次onCreate()时创建,然后直到最后Activity销毁。

ViewModel相关类图

ViewModelProviders是ViewModel工具类,该类提供了通过Fragment和Activity得到ViewModel的方法,而具体实现又是由ViewModelProvider实现的。

ViewModelProvider是实现ViewModel创建、获取的工具类。在ViewModelProvider中定义了一个创建ViewModel的接口类——Factory。ViewModelProvider中有个ViewModelStore对象,用于存储ViewModel对象。

ViewModelStore是存储ViewModel的类,具体实现是通过HashMap来保存ViewModle对象。

ViewModel是个抽象类,里面只定义了一个onCleared()方法,该方法在ViewModel不在被使用时调用。ViewModel有一个子类AndroidViewModel,这个类是便于要在ViewModel中使用Context对象,因为我们前面提到不能在ViewModel中持有Activity的引用。

ViewModelStores是ViewModelStore的工厂方法类,它会关联HolderFragment,HolderFragment有个嵌套类——HolderFragmentManager。

ViewModel相关时序图

追溯创建一个ViewModel的源码,会察觉需要的步骤有点多。下面以在Fragment中得到ViewModel对象为例看下整个过程的时序图。

时序图看起来比较复杂,但是它只描述了两个过程:

得到ViewModel对象。
HolderFragment被销毁时,ViewModel收到onCleared()通知。

ViewModel相关源码分析

ViewModelProviders类的具体实现:

public class 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);
}

ViewModelProviders提供了四个of()方法,四个方法功能类似,其中of(FragmentActivity activity, Factory factory)和of(Fragment fragment, Factory factory)提供了自定义创建ViewModel的方法。

  1. 判断Fragment的是否Attached to Activity,Activity的Application对象是否为空。
  2. 创建ViewModel对象看似很简单,一行代码搞定。

new ViewModelProvider(ViewModelStores.of(fragment), factory)

先看看ViewModelStores.of()方法:

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

继续深入发现其实是实现了一个接口:

public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}

holderFragmentFor()是HolderFragment的静态方法,HolderFragment继承自Fragment。我们先看holderFragment()方法的具体实现

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}

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

继续看HolderFragmentManager.holderFragmentFor()方法的具体实现

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;
}

private FragmentLifecycleCallbacks mParentDestroyedCallback =
new FragmentLifecycleCallbacks() {
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
super.onFragmentDestroyed(fm, parentFragment);
HolderFragment fragment = mNotCommittedFragmentHolders.remove(
parentFragment);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
}

最后

题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

Android开发8年,阿里、百度一面惨被吊打!我是否应该转行了?

【Android进阶学习视频】、【全套Android面试秘籍】

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值