最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面。
Android Architecture组件是Android Jetpack的一部分,它们是一组库,旨在帮助开发者设计健壮、可测试和可维护的应用程序,包含一下组件:
上述时Android Architecture所提供的架构组件,本文主要从使用和源码的角度了解一下ViewModel组件的机制
Android框架管理UI控制器的生命周期,例如活动和片段。框架可以决定销毁或重新创建UI控制器以响应完全不受您控制的某些用户动作或设备事件,那设想一种情况当用户在界面操作录入了一些信息后,因为某种原因导致Activity重新创建,那此时用户写好的信息呢?如果要重头再来可能有的用户就会不耐烦了,进而减少了使用。。。,可能有人说,可以使用该 onSaveInstanceState()方法并从包中恢复其数据 onCreate(),但此方法仅适用于可以序列化然后反序列化的少量数据,如果要恢复的数据量比较大,此时就时VIewModel的厉害之处了。
ViewModel之所以能在Activity重建时保存并恢复数据,因为Activity初次创建时会初始化创建VIewModel,在Activity销毁时,ViewModel对象不会销毁,在新的Activity重新创建后,仍然会执行之前的获取ViewModel的过程,Android系统采取了处理机制,使现在拿到的ViewModel就是前一次创建的对象,设想一下数据都储存在VIewModel中,而两次拿到的都是同一个VIewModel,那显示的数据自然就和之前的一样喽,这里先放一张系统处理ViewModel的创建、存储和获取流程图:
class Model : ViewModel() {
var textName = "Empty"
}
val model = ViewModelProviders.of(this)[Model::class.java]
tvModel.text = model.textName
btn_change.setOnClickListener {
model.textName = "Change = 22222"
tvModel.text = model.textName
}
5.1 、ViewModelProviders.of(this)[Model::class.java]
从上面的方法中可以看出ViewModel的获取过程分为两步:
ViewModelProviders提供四个构造方法创建VIewProvider,两个带有factory两个没有,不过没有factory的其实使用的是默认的Factory,所以四个方法基本一致只是Fragment和Activity的区分
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
return of(fragment, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
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(ViewModelStores.of(fragment), factory);
}
@NonNull
@MainThread
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(ViewModelStores.of(activity), factory);
}
@NonNull
@MainThread
public T get(@NonNull String key, @NonNull Class 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;
}
上面的执行是,先去ViewModelStore中获取,如果为空就调用Factory的create()创建ViewModel,并储存在VIewmoStore中,与我们所想一致;
5.2 、VIewModelStore
上述过程中使用ViewModelStore.of(this) 创建ViewModelStore,方法源码:
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
先判断Activity是否为 ViewModelStoreOwner,如果是直接获取其中的ViewModelStore,否则调用holderFragmentFor(activity).getViewModelStore()获取
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
// HolderFragmentManger
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm); // 根据TAG查找Fragment
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); // 创建HolderFragment
mNotCommittedActivityHolders.put(activity, holder); // 保存到集合
return holder;
}
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
// 根据TAG查找
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
...
return (HolderFragment) fragmentByTag;
}
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss(); // 设置TAG
return holder;
}
5.3、HolderFragment
上面的过程都是获取或创建HolderFragment的过程,有没有想过我们要的是储存ViewModel的地方,为什么一值在操作Fragment,答案就在其中:
public class HolderFragment extends Fragment implements ViewModelStoreOwner {
}
private ViewModelStore mViewModelStore = new ViewModelStore();
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
private final HashMap 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);
}
整个ViewModel的源码分析到此结束了,总结一下内部的储存逻辑
在上面获取Fragment中时,创建过HolderFragment后保存在Map中,现在我们看一下这个map
private Map mNotCommittedActivityHolders = new HashMap<>();
Map的键就是Activity的实例,所以无论多少次创建都是此Activity的实例,也就获得唯一的一个对应的Fragment
按照上一个问题的逻辑,主要是传入的Activity的对象一致,那获取到就是同一个Fragment,存储的也是同一个VIewStore,那设想一下,如果一个Activity中有多个Fragment,利用这个特性就可以实现数据交互了;例如:两个Fragment之间。一个显示标题列表,点击某一个标题,另一个Fragment显示内容,此时使用一个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 onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item); // 设置数据
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
到此ViewModel的介绍完成了,将ViewModel和LiveData或其他组件联合使用,构造数据驱动型的界面,相信一定会带来不一样的体验。