本篇文章主要是介绍lifecycle-runtime-ktx的两个大家用的比较少的API:findViewTreeLifecycleOwner和withCreated/Started/Resumed() 系列。
View.findViewTreeLifecycleOwner()
这个是ifecycle-runtime-ktx
官方库提供的一个扩展方法简化获取LifecycleOwner
的逻辑:
public fun View.findViewTreeLifecycleOwner(): LifecycleOwner? = ViewTreeLifecycleOwner.get(this)
最终调用:
public static LifecycleOwner get(@NonNull View view) {
LifecycleOwner found = (LifecycleOwner) view.getTag(R.id.view_tree_lifecycle_owner);
if (found != null) return found;
ViewParent parent = view.getParent();
while (found == null && parent instanceof View) {
final View parentView = (View) parent;
found = (LifecycleOwner) parentView.getTag(R.id.view_tree_lifecycle_owner);
parent = parentView.getParent();
}
return found;
}
可以看到最终是遍历view树,从View的tag
中通过R.id.view_tree_lifecycle_owner
获取的:
@UnsupportedAppUsage
//键值为非装箱的基本数据类型int
private SparseArray<Object> mKeyedTags;
public Object getTag(int key) {
if (mKeyedTags != null) return mKeyedTags.get(key);
return null;
}
我们看下这个tag
是在哪里赋值的:
看下AppCompatActivity
的setContentView()
方法:
@Override
public void setContentView(@LayoutRes int layoutResID) {
initViewTreeOwners();
getDelegate().setContentView(layoutResID);
}
走进initViewTreeOwners()
方法看下:
private void initViewTreeOwners() {
ViewTreeLifecycleOwner.set(getWindow().getDecorView(), this);
...
}
//ViewTreeLifecycleOwner.java
public static void set(@NonNull View view, @Nullable LifecycleOwner lifecycleOwner) {
view.setTag(R.id.view_tree_lifecycle_owner, lifecycleOwner);
}
可以看到,就是在这里进行赋值的,其中这个参数view就是DecorView
。
LifecycleOwner.withCreated/Started/Resumed()
这里我们以LifecycleOwner.withStarted()
举例,这个方法是带有返回值
的且保证在主线程执行
,在未达到指定执行生命周期且返回结果执行完毕之前,运行的协程会进行挂起:
public suspend inline fun <R> LifecycleOwner.withStarted(
crossinline block: () -> R
): R = lifecycle.withStateAtLeastUnchecked(
state = Lifecycle.State.STARTED,
block = block
)
最终走到lifecycle.withStateAtLeastUnchecked()
方法:
@PublishedApi
internal suspend inline fun <R> Lifecycle.withStateAtLeastUnchecked(
state: Lifecycle.State,
crossinline block: () -> R
): R {
//1.指定主线程调度器,判断是否需要分发
val lifecycleDispatcher = Dispatchers.Main.immediate
val dispatchNeeded = lifecycleDispatcher.isDispatchNeeded(coroutineContext)
//2.直接执行,无需分发
if (!dispatchNeeded) {
if (currentState == Lifecycle.State.DESTROYED) throw LifecycleDestroyedException()
if (currentState >= state) return block()
}
//3.挂起执行
return suspendWithStateAtLeastUnchecked(state, dispatchNeeded, lifecycleDispatcher) {
block()
}
}
接下来我们来一步步进行分析:
Dispatchers.Main.immediate
代表主线程调度器,通过isDispatchNeeded
判断当前的执行环境是否处于主线程,如果是将执行执行协程代码块,否则需要调度器分发到主线程再进行执行。
STARTED
直接进行执行STARTED
挂起协程下面走进suspendWithStateAtLeastUnchecked()
函数:
@PublishedApi
internal suspend fun <R> Lifecycle.suspendWithStateAtLeastUnchecked(
state: Lifecycle.State,
dispatchNeeded: Boolean,
lifecycleDispatcher: CoroutineDispatcher,
block: () -> R
): R = suspendCancellableCoroutine { co ->
val observer = object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.upTo(state)) {
removeObserver(this)
//2.达到执行`Started`状态恢复挂起的协程
co.resumeWith(runCatching(block))
} else if (event == Lifecycle.Event.ON_DESTROY) {
removeObserver(this)
//3.达到`DESTROYED`状态抛出异常
co.resumeWithException(LifecycleDestroyedException())
}
}
}
//1.添加观察者
if (dispatchNeeded) {
lifecycleDispatcher.dispatch(
EmptyCoroutineContext,
Runnable { addObserver(observer) }
)
} else addObserver(observer)
//3.移除观察者
co.invokeOnCancellation {
if (lifecycleDispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
lifecycleDispatcher.dispatch(
EmptyCoroutineContext,
Runnable { removeObserver(observer) }
)
} else removeObserver(observer)
}
}
首先说明下suspendWithStateAtLeastUnchecked()为什么使用@PublishedApi注解修饰,由于内联函数中调用的方法只能是public方法,而suspendWithStateAtLeastUnchecked()是个internal,所以需要增加该注解声明。
suspendCancellableCoroutine()方法捕捉Continuation并决定被挂起的协程的恢复时机。
这个就是为了兜底,一般都是建议使用Activity的lifecycleScope
或viewModel
的viewModelScope
作为协程作用域,因为这两个是和对应组件的生命周期绑定的,这样当组件销毁/清楚,该作用域下的子协程就会被取消,我们通过invokeOnCancellation{}
监听到,可以执行一些资源的释放工作,比如这里的取消观察者的注册。
lifecycle-runtime-ktx
库中其他的扩展方法大家都比较熟悉,这里就不再额外进行介绍了.
阅读量:1274
点赞量:0
收藏量:0