Android Architecture Components是Google为开发者提供的架构设计方案,里面包含若干内容:
- Lifecycle
- ViewModel
- LiveData
- Room
- Paging
具体介绍和教程见官网,暂时项目用得上是前三个,重点吹吹ViewModel和LiveData。Room是官方提供的对SQLite的抽象,知道它的存在就好,没有找到取代greenDAO或者realm的理由。Paging支持对RecyclerView分页加载,可以期待,但现在版本还是1.0.0rc,先放一边。
现在最新的版本:android.arch.lifecycle:extensions:1.1.1
Lifecycle
向上找Activity的父类,在SupportActivity里实现了LifecycleOwner,里面只有一个方法getLifecycle。(某个版本api添加的哈,人懒没有去查是几)
在onCreate可以将Activity的生命周期委托给LifecycleObserver:
lifecycle.addObserver(MyLifecycleObserver())
LifecycleObserver是一个接口,我们使用@OnLifecycleEvent绑定生命周期和具体的函数。除了ON_CREATE等基本的,还添加了ON_ANY。
class MyLifecycleObserver : LifecycleObserver {
companion object {
val LIFECYCLE_TAG = TAG + "lifecycle"
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
LogUtils.d("$LIFECYCLE_TAG-onCreate")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
LogUtils.d("$LIFECYCLE_TAG-onStart")
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
fun onAny() {
//LogUtils.d("$LIFECYCLE_TAG-onAny")
}
}
使用Lifecycle好处显而易见,Activity生命周期的函数不用散落到各处,可以统一在一个地方处理好。
ViewModel和LiveData
ViewModel就是MVVM模式中的VM,默认你认识MVVM和databinding,写个demo。
Activity里有两个Fragment(红色是Fragment1、蓝色是Fragment2),通过“上一页”、“下一页”切换。有一个持久化的user对象,包括“name”和“age”两个属性,点击按钮“更新user”,变更user对象的属性并显示在两个Fragment中。
功能很简单,但是需要处理常见的Fragment间通信。假如使用MVP模式,每个Fragment对应一个Presenter。两个Fragment之间的通信,要不使用Activity传递参数,要不使用RxBus之类的事件总线,ViewModel提供更简单的方法。
首先介绍LiveData,可以包装任意类型的对象,它有三个特点:
- 供观察者订阅
- 感知组件(Activity、Fragment、Service)生命周期
- 提供活跃状态,活跃的才通知观察者
在ViewModel自定义一个init函数,创建User对象的LiveData:
private lateinit var userData: LiveData<User>
fun init() {
val user = createUser()
this.userData = userRepository.getUser(user.userId)
}
userRepository是M层的对象,我这里使用了ROOM,它可以直接返回对象的LiveData。如果是其他持久化库,返回的user对象可以手动setValue进MutableLiveData。MutableLiveData是LiveData的子类,可以修改值,还有一个子类MediatorLiveData,可以观测一个或多个LiveData的变化,用到再说了。
更新值有两个方法,一个是postValue,一个是setValue。前者可以在任意线程,后者只能在主线程。
在Activity里获取ViewModel:
val viewModel = ViewModelProviders.of(this).get(PersonalDetailViewModel::class.java)
在Fragment里获取ViewModel:
val viewModel = ViewModelProviders.of(activity!!).get(PersonalDetailViewModel::class.java)
两者非常相似,要注意of函数传入的参数,无论是Activity还是Fragment,都是传入activity对象,这样保证它们获取同一个ViewModel。(Activity里有个Map保存ViewModel)
viewModel.getUserData().observe(this, Observer<User> { user ->
user?.let {
tv_name.text = user.name
tv_age.text = user.age.toString()
}
})
在Fragment2中通过observe订阅LiveData变化,当Fragment1修改User属性,Fragment2触发Observer的onChanged函数,我们对应修改ui显示。只要订阅了LiveData,任意地方都可以即时知道。
既然有订阅观察,为什么没有写对应的解绑订阅?这就是LiveData的第二个特点,注意到observe传入的参数是LifecycleOwner,它是可以感知组件的生命周期。当生命周期是DESTORY时,自动解绑订阅,具体后面分析源码就知道了。
也有另外一个observeForever函数,不需要传入LifecycleOwner,但是需要手动使用remove,和普通的观察者模式一样。
还有第三个特点,活跃状态。这个很好理解,组件处于某些状态时,才通知观察者变化。
LiveData源码分析
知其然知其所以然,顺手看看ViewModel和LiveData的实现方式。
LiveData是典型的观察者模式,使用自定义的SafeIterableMap保存所有观察者。
private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
键值对类型<Observer<T>, ObserverWrapper>,Observer是观察者对象,ObserverWrapper是什么东西,观察者的包装类?
private abstract class ObserverWrapper {
final Observer<T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
//...
}
果然ObserverWrapper包装了Observer,增加了active和version。LifecycleBoundObserver是ObserverWrapper的抽象实现类,包含了生命周期LifecycleOwner。他们的联系很清楚了,对Observer的管理叠加了生命周期,看LifecycleBoundObserver其中两个函数:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
//...
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
//...
}
当生命周期变为DESTROYED时,自动移除观察者,实现上节所讲感知组件生命周期。当组件处于活跃时,观察才是有效的,这里需要生命周期至少是STARTED。最后调用ObserverWrapper.activeStateChanged处理生命周期变化。
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
onActive和onInactive是两个空函数,可以让LiveData的子类额外处理活跃变化。处于活跃时,调用dispatchingValue通知观察者。具体的通知过程路过,不外乎是循环所有观察者,根据条件调用onChange函数。
最后看回LiveData的订阅函数observe,有了上面的分析,都不用讲了。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
ViewModel源码分析
ViewModel是一个抽象类,里面只有一个clear函数,需要时可以重写做些清理。
public abstract class ViewModel {
protected void onCleared() {
}
}
使用ViewModel的入口函数在ViewModelProviders,核心是函数of,区分入参Fragment和Activity两个版本。
@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);
}
of返回的对象是ViewModelProvider,和ViewModelProviders差了个s。
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
创建ViewModelProvider需要两个对象:
- ViewModelStore
- Factory
Factory
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
Factory接口,只有一个函数create,传入class,创建ViewModel。AndroidViewModelFactory是它的实现类:
//AndroidViewModelFactory
@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...
}
return super.create(modelClass);
}
通过isAssignableFrom判断class类型是不是AndroidViewModel,是的话创建带Application实例的AndroidViewModel。不是的话,创建工作交给父类NewInstanceFactory,对应的create函数创建无参构造函数的普通ViewModel。
//NewInstanceFactory
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
}
//catch...
}
ViewModelStore
private final HashMap<String, ViewModel> mMap = new HashMap<>();
ViewModelStore很简单,里面有一个HashMap,保存key和ViewModel。很明显它是ViewModel的缓存,可以使用get和put操作。
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
ViewModelStore通过调用ViewModelStores.of获取,有两种获取来源:
- 第一种,ViewModelStore对象保存在Activity和Fragment,它们都实现了ViewModelStoreOwner接口。因此,可以很轻松在Activity或Fragment得到我们需要的ViewModel对象。
- 第二种,ViewModelStoreOwner接口是某个时候加入Activity的,如果之前的没有实现接口又怎样办?
大神们弄了个HolderFragment承载ViewModelStore:
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;
}
就是这个方法createHolderFragment,动态将HolderFragment添加进Activity,然后就可以获取ViewModelStore了。
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
Fragment里添加HolderFragment类似,用的是ChildFragmentManager。
ViewModelProvider.get()
最后一步,从ViewModelProvider获取ViewModel的get函数:
@NonNull
@MainThread
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);
}
@NonNull
@MainThread
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;
}
ViewModel存在于ViewModelStore时直接获取,否则创建并加入ViewModelStore,key的构成是固定字符串加上类的canonicalName。
总结
可以用