当编写Views
时,ViewModels
和LiveData
是生命周期感知的。ViewModel
想要的是当前FragmentActivity
,LiveData
当前LifecycleOwner
。您事先不知道您的视图是否会被包装或有些。因此,它需要一个灵活的函数来查找所需的上下文。我最终得到了这两种方法:
private FragmentActivity getFragmentActivity() {
Context context = getContext();
while (!(context instanceof FragmentActivity)) {
context = ((ContextWrapper) context).getBaseContext();
}
return (FragmentActivity) context;
}
private LifecycleOwner getLifecycleOwner() {
Context context = getContext();
while (!(context instanceof LifecycleOwner)) {
context = ((ContextWrapper) context).getBaseContext();
}
return (LifecycleOwner) context;
}
现在,这是要放入每个视图的大量样板代码。有没有更简单的方法?
我不想为此使用自定义的 View 基类,因为大型层次结构很丑陋。另一方面,组合需要与此解决方案一样多的代码。
你可以找到它 lifecycle-runtime-ktx
:
fun View.findViewTreeLifecycleOwner(): LifecycleOwner? = ViewTreeLifecycleOwner.get(this)
Kotlin 扩展
fun Context.fragmentActivity(): FragmentActivity? {
var curContext = this
var maxDepth = 20
while (--maxDepth > 0 && curContext !is FragmentActivity) {
curContext = (curContext as ContextWrapper).baseContext
}
return if(curContext is FragmentActivity)
curContext
else
null
}
fun Context.lifecycleOwner(): LifecycleOwner? {
var curContext = this
var maxDepth = 20
while (maxDepth-- > 0 && curContext !is LifecycleOwner) {
curContext = (curContext as ContextWrapper).baseContext
}
return if (curContext is LifecycleOwner) {
curContext as LifecycleOwner
} else {
null
}
}
用法
val lifecycleOwner = context.lifecycleOwner()
val fragmentActivity = context.fragmentActivity()
类似于另一个答案,但不需要指定 maxDepth:
val Context.lifecycleOwner: LifecycleOwner?
get() {
var context: Context? = this
while (context != null && context !is LifecycleOwner) {
val baseContext = (context as? ContextWrapper?)?.baseContext
context = if (baseContext == context) null else baseContext
}
return if (context is LifecycleOwner) context else null
}
如果你不想使用组合,你可以把它放到公共的BaseView类中。 或者,您可以在某些 utils 类中使其成为静态方法。
如果你使用 Kotlin,你也可以让它成为 Kotlin 扩展函数,我最喜欢的方式是什么。