Android Architecture Components源码分析

在分析Android Architecture Component这个框架之前,先想想这个框架能为我们做什么,我们为什么要按照这套框架模式去构建app?它和MVP架构有什么区别?

MVP, Clean, AAC架构的特点:
MVP架构的特点是面向接口编程。在View, Presenter, Model之间分别用接口做衔接,当有新的底层实现时,能够无缝替换。

此外,MVP的View和Model并不产生依赖,因此可以说是对View和Model做了解耦。

但MVP架构有其局限性。MVP需要创建太多的类和接口,并且每次通信都需要繁琐的通过接口传递信息

google sample提供了一个todo-mvp sample, 里面有MVP+RxJava实现,Clean架构实现。这两种架构方式我都实践过,MVP+RxJava所有业务,UI逻辑都包含在Presenter里面, Presenter直接干预了UI在拿到数据后做什么,使得逻辑上没有发生解耦,正常来说,解耦意味着Presenter的只能边界仅限返回结果数据,由UI来根据数据处理UI逻辑。

Clean架构将业务逻辑分解成可重用的更小粒度的usecase, 业务逻辑的职能被转移到领域层,Presenter则弱化为ViewModel, 作为代理数据请求和衔接数据回调的缓冲区。

Clean 架构的特点是单向依赖、数据驱动编程。 View -> ViewModel -> Usecase -> Model.

但 Clean 架构也有不足:粒度太细 。一个 Usecase 受限于请求参数,因而只能处理一类请求。View请求求的数据包含几种类型,就至少需要准备几个 Usecase。Usecase是依据当前View对数据的需求量身定制的,且形式大同小异,因此Usecase的复用率极低,项目会因而急剧的增加类和重复代码。

AAC也是数据驱动编程。直接在View中写个观察者回调,以接收结果数据并处理UI逻辑。MVP架构中Presenter直接引用View,告诉View该显示什么,而AAC中的View持有ViewModel的引用,ViewModel不需要持有View的引用,而是根据View绑定的事件进行流式调用,这也意味着MVP架构中以来的回调接口也用不着了。

数据的消费者应该知道生产者,但生产者(ViewModel)不知道也不关心谁消费了数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void subscribeUi(ProductListViewModel viewModel) {
// Update the list when the data changes
viewModel.getProducts().observe(this, new Observer<List<ProductEntity>>() {
@Override
public void onChanged(@Nullable List<ProductEntity> myProducts) {
if (myProducts != null) {
mBinding.setIsLoading(false);
mProductAdapter.setProductList(myProducts);
} else {
mBinding.setIsLoading(true);
}
// espresso does not know how to wait for data binding's loop so we execute changes
// sync.
mBinding.executePendingBindings();
}
});
}

除此之外,Fragment.setRetainInstance(boolean retain
)方法设置为true, 保证Configuration change的时候与该fragment关联的数据能够保存。

AAC是由一系列库组成,能够帮助我们管理UI组件的生命周期和处理数据存留。生命周期感知组件可以管理Activity和Fragment的生命周期,在configuration change的时候可以保留现场数据并重新更新UI,避免内存泄漏。

使用LiveData构造数据对象,当底层数据发生变化时就会通知更新UI.

ViewModel存储UI相关的数据,在app旋转时不会销毁。

Lifecycle如何与Activity, Fragment的生命周期绑定?
Lifecycle定义了一个拥有Android生命周期的对象,Activity, Fragment实现了LifecycleOwner接口,可以直接访问到Lifecycle.

1
2
3
4
5
6
7
8
9
public class ComponentActivity extends Activity
implements LifecycleOwner {


@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}

}

Lifecycle定义了两个枚举类型Event和State, State可以看做图的节点,State定义了一系列与生命周期相关的状态,Event则可以看做图的路径。Lifecycle负责保存并更新当前生命周期状态。

刚好在Activity.onDestroy()调用之前,达到DESTROYED状态,处于DESTROYED状态的Lifecycle对象不会再传递任何事件Event.

INITIALIZED状态在Lifecycle对象已创建但还未调用Activity.onCreate()之前。

在Activity.onCreate()调用之后,Activity.onStop()调用之前处于CREATED状态。

在Activity.onStart()调用之后,Activity.onPause()调用之前处于STARTED状态。

在Activity.onResume()调用之后处于RESUMED状态。

接下来看看状态的转化。

什么时候处于INITIALIZED状态呢?

首先来看一下生命周期感知组件的类关系图

Lifecycle定义成一个拥有Android生命周期的接口对象。Fragment或FragmentActivity实现了LifecycleOwner接口,并通过getLifecycle方法获取LifecycleRegistry对象。LifecycleRegistry实现了Lifecycle,能够处理多个观察者。

LifecycleRegistry定义了内部嵌套类ObserverWithState,通过调用addObserver方法我们将参数LifecycleObserver对象传入,并封装成了ObserverWithState对象,在handleLifecycleEvent接收到外部传入的Event事件,计算出目标状态,最后调用GenericLifecycleObserver的onStateChanged方法通知状态的变换。


当应用程序启动时,会注册清单文件里声明的ContentProvider, 在框架里就是ProcessLifecycleOwnerInitializer, 可以到app/build/outputs/logs/manifest-merge-debug-report.txt找到ProcessLifecycleOwnerInitializer类所在的清单文件位置,最终清单文件会合并到打包完成的应用中来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.lifecycle.process" >

<uses-sdk android:minSdkVersion="14" />

<application>
<provider
android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
android:authorities="${applicationId}.lifecycle-process"
android:exported="false"
android:multiprocess="true" />
</application>

</manifest>

ProcessLifecycleOwnerInitializer只干一件事,注册ActivityLifecycleCallbacks,具体是使用一个无UI的ReportFragment, 利用Fragment的生命周期回调将Lifecycle Event发布出去。

1
2
3
4
5
6
7
8
9
public class ProcessLifecycleOwnerInitializer extends ContentProvider {
@Override
public boolean onCreate() {
LifecycleDispatcher.init(getContext());
ProcessLifecycleOwner.init(getContext());
return true;
}
...
}

ProcessLifecycleOwner提供了整个应用进程的生命周期,Lifecycle.Event.ON_CREATE事件只会发布一次,而Lifecycle.Event.ON_DESTROY则不会发布。Lifecycle.Event.ON_PAUSE和Lifecycle.Event.ON_STOP事件则会在上一个Activity走完对应生命周期方法后延时发布。这个延时时间足够长,确保当configuration change导致Activity销毁,重建时不会重新发布对应事件。

当我们需要监听应用从后台回到前台或者从前台到后台时,这个类就变得很有用。
我们可以在自定义Application中添加观察者,监听到ON_START事件表示应用回到前台,监听ON_STOP事件表示应用回到了后台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BasicApp extends Application {
private static final String TAG = BasicApp.class.getSimpleName();


@Override
public void onCreate() {
super.onCreate();

ProcessLifecycleOwner.get().getLifecycle().addObserver(new GenericLifecycleObserver() {
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
Log.d(TAG, "ProcessLifecycleOwner onStateChanged, event: " + event);
}
});
}
}

根据上图我们再来梳理一下ProcessLifecycleOwner发布消息的流程。
1.程序启动时,ProcessLifecycleOwner完成初始化,注册ActivityLifecycleCallbacks, 对ReportFragment设置监听器处理Fragment对应的onStart(), onResume()回调。

2.用户启动Activity, ReportFragment通过回调通知ProcessLifecycleOwner发送Lifecycle.Event.ON_START事件,并将计数器mStartedCounter加1,mStopSent置为false. 接下来收到onResume()回调,将计数器mResumedCounter加1,发送Lifecycle.Event.ON_RESUME事件,mPauseSent置为false.

3.用户启动一个新的Activity, ProcessLifecycleOwner注册的ActivityLifecycleCallbacks收到onActivityPaused回调,将计数器mResumedCounter减1,并将Lifecycle.Event.ON_PAUSE事件延时处理。如果在这段事件内configuration change导致Activity销毁并重建的话,那么计数器mResumedCounter, mStartedCounter值将发生改变,Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP事件将不会发布。当整个应用最后一个Activity销毁的时候,就会发布Lifecycle.Event.ON_STOP事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void activityResumed() {
mResumedCounter++;
if (mResumedCounter == 1) {
if (mPauseSent) {
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
mPauseSent = false;
} else {
mHandler.removeCallbacks(mDelayedPauseRunnable);
}
}
}

void dispatchPauseIfNeeded() {
if (mResumedCounter == 0) {
mPauseSent = true;
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
}

void dispatchStopIfNeeded() {
if (mStartedCounter == 0 && mPauseSent) {
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
mStopSent = true;
}
}