Jetpack 源码分析系列:
本文主要内容:
前面我们介绍了 Jetpack 中的 Lifecycle
和 ViewModel
组件,今天我们来看下 Jetpack 中的 LiveData
组件的使用及原理分析。
根据官方文档对 LiveData 的介绍,LiveData 主要由如下几个特点:
LiveData 能够感知组件的生命周期,那么它肯定依赖 Lifecycle 这个组件的,关于 Lifecycle 组件已经在前面分析过了:《Android Jetpack(一) Lifecycle 组件原理剖析》。
一般 LiveData 放在 ViewModel 中使用,关于 ViewModel 组件也在前面分析过了:《Android Jetpack(二)ViewModel 组件原理剖析》。
理解 Lifecycle 是理解 LiveData 工作原理的的前提。
下面我们通过一个简单的案例来认识下 LiveData,然后借助这个案例对 LiveData 的工作机制做一个分析。
Demo 的效果还是和介绍 ViewModel 的时候一样的:
只不过实现的方式有一些细微的差别,完整的代码如下所示:
LiveDataDemoActivity.kt
class LiveDataDemoActivity : BaseActivity() {
private lateinit var myViewModel: LiveDataViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewmodel_demo_layout)
myViewModel = ViewModelProvider(this).get(LiveDataViewModel::class.java)
myViewModel.liveData.observe(this, Observer {
text_number.text = "$it"
})
btn_plus.setOnClickListener {
myViewModel.plus(1)
}
}
}
LiveDataViewModel.kt
class LiveDataViewModel : ViewModel() {
val liveData: MutableLiveData by lazy {
MutableLiveData().apply {
value = 0
}
}
fun plus(num: Int) {
liveData.value = liveData.value?.plus(num)
}
}
上面的实现方式和介绍 ViewModel 时的案例区别在于,数据不直接放在 ViewModel 中,而是放在 LiveData 中,然后 ViewModel 持有这个 LiveData
在界面中调用 liveData.observer
来监听数据的变化,就这么简单,不需要在生命周期方法中做任何特殊处理,LiveData 只会在组件被激活的状态下(start、resume)通知 Observer。
下面我们就来分析下 LiveData 的工作原理。
看完上面的效果图和对应的实现代码,读者可能有些疑问,例如在 configuration changes
的时候界面上为什么能够展示上次的数据,我们并没有在 onCreate 方法中直接为控件设置数据,而是在 liveData.observe 方法的回调中为控件设置数据的。那说明应该是在某个生命周期触发了这个 observer 回调的,由此可见有两种方式来触发 observer 回调:一个是在生命周期方法触发的时候自动触发;一个是手动调用 liveData.setValue 方式触发。
在上面的案例中我们在 ViewModel 中持有了 LiveData,那么在 configuration changes
界面重建的时候获取到的 ViewModel 对象是同一个,这个已经在前面介绍了过了,在这里就不赘述了。既然 ViewModel 是同一个,那么里面的 LiveData 对象也是同一个。
然后我们来看下上面调用的 livedata.observer
方法:
public abstract class LiveData {
// 省略其他代码...
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 将 owner 和 observer 组装成新的对象 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 如果容器中已经存在,并且和 owner 绑定过,则抛出异常
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);
}
}
上面最关键的一行代码为:
owner.getLifecycle().addObserver(wrapper);
这段代码很熟悉,这不就是我们介绍 Lifecycle 源码的时候介绍的吗,在这里我就不赘述了,不了解了 Lifecycle 的可以查看之前的文章。
简而言之就是将观察者放进容器中,然后在生命周期触发的时候调用里面的 observer 回调。
那么就上面的案例中的 observer :
来说不就会被调用很多次(onCreate,onStart,onResume)吗?事实上只会在 onStart 的时候调用一次:
myViewModel.liveData.observe(this, Observer {
text_number.text = "$it"
})
从上面的 observe 方法源码中我们知道,该方法会将 owner 和 observer 组装成新的对象 LifecycleBoundObserver
,然后放进容器中。
我们来看下 LifecycleBoundObserver
:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
// 如果当前的状态为 DESTROYED ,则从容器中移除 observer
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// 当前状态为 START 才会通知 observer
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
LifecycleBoundObserver
继承自 ObserverWrapper
:
private abstract class ObserverWrapper {
final Observer super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
// 如果当前的状态和 newActive 一样则跳过
// 都是 false 或者都是 true
// 例如在 onCreate(都是false)、onResume(都是true)都会跳过
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) {
// 真正的通知 observer
dispatchingValue(this);
}
}
}
上面的代码有两个重要的方法:shouldBeActive、activeStateChanged
尽然是依赖 Lifecycle 组件,那么当触发生命周期的时候,肯定会触发里面的 Observer,LiveData 为了避免 Observer 被通知多次,通过 shouldBeActive
方法来判断是否应该被通知。所以在 START
状态会被通知,那么 RESUME
是不是也会通知呢,它也是 active 状态,其实不会,应该 LiveData 里面会有变量记录当前的是否为激活状态,如果该变量和 shouldBeActive 放回的值一样则 return:
void activeStateChanged(boolean newActive) {
// 如果当前的状态和 newActive 一样则跳过
// 都是 false 或者都是 true
// 例如在 onCreate(都是false)、onResume(都是true)都会跳过
if (newActive == mActive) {
return;
}
// 省略其他代码
}
因为在 START
状态的时候已经将 mActive
变量设置为 true
了,当 RESUME
的时候 newActive
也是 true
,所以直接 return。
了解完了 Observer 的触发时机,我们看下最终的触发 Observer 回调的方法:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 如果当前正在分发数据,则 return
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 如果 initiator 不为空,则考虑通知 observer
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
// 如果 initiator 为空,则遍历整个 observer 集合
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
// 如果为未激活状态
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 将 LiveData 持有的数据回传给 observer
observer.mObserver.onChanged((T) mData);
}
至此,我们就将 LiveData 组件的原理介绍完毕了,其实也挺简单的,当然我们是基于理解了 Lifecycle 和 ViewModel 的前提之下的。希望对你有帮助。
上面的案例我们只是简单的把数据写死在 LiveData 中,并没有从本地或者服务器获取数据。在实际的开发中一般是 LiveData 操作 Repository。
在这里我们使用 Retrofit 来作为网络请求库。Retrofit 官方没有推出整合 LiveData 的依赖,需要我们自定义 CallAdapter:
class LiveDataCallAdapterFactory : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array?, retrofit: Retrofit?): CallAdapter<*, *>? {
if (getRawType(returnType) != LiveData::class.java) {
return null
}
check(returnType is ParameterizedType) {
"LiveData must have generic type (e.g., LiveData)"
}
val type = getParameterUpperBound(0, returnType)
return LiveDataCallAdapter(type)
}
class LiveDataCallAdapter(private var type: Type) : CallAdapter> {
override fun adapt(call: Call): LiveData {
return object : LiveData() {
val flag = AtomicBoolean(false)
override fun onActive() {
super.onActive()
if (flag.compareAndSet(false, true)) {
call.enqueue(object : Callback {
override fun onFailure(call: Call?, t: Throwable?) {
t?.printStackTrace()
postValue(null)
}
override fun onResponse(call: Call?, response: Response?) {
postValue(response?.body())
}
})
}
}
}
}
override fun responseType(): Type {
return type
}
}
}
然后在 ViewModel 中使用:
class GithubViewModel : ViewModel() {
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com")
// 添加自定义的 CallAdapterFactory
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
private var githubService: Github = retrofit.create(Github::class.java)
fun getContributors(owner: String?, repo: String?): LiveData?>? {
return githubService.contributors(owner, repo)
}
}
最后在 Activity 中监听 ViewModel 数据的变化:
class RetrofitLiveDataDemoActivity : BaseActivity() {
private val myViewModel: GithubViewModel by viewModels {
GithubViewModelFactory()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_retrofit_livedata_layout)
text_log.text = "Square's retrofit contributors:\n"
myViewModel.getContributors("square", "retrofit")?.observe(this, Observer {
it?.forEach { contributor: Contributor? ->
text_log.append("\nname: ${contributor?.login} - count: ${contributor?.contributions}")
}
})
}
}
程序运行如下图所示:
本文详细为大家介绍了 Jetpack LiveData
组件使用及原理分析,最后通过自定义 CallAdapter
整合了 Retrofit 和 ViewModel。
另外本文涉及到的代码都在我的 AndroidAll GitHub 仓库中。该仓库除了 Jetpack
,还有 Android 程序员需要掌握的技术栈,如:程序架构、设计模式、性能优化、数据结构算法、Kotlin、Flutter、NDK,以及常用开源框架 Router、RxJava、Glide、LeakCanary、Dagger2、Retrofit、OkHttp、ButterKnife、Router 的原理分析 等,持续更新,欢迎 star。