Простой способ получить текущую активность, фрагмент, LifeCycleOwner из View?
При написании 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. Есть ли более простой способ?
Я не хочу использовать настраиваемый базовый класс View для этого, так как большие иерархии ужасны. Композиция, с другой стороны, требует столько же кода, сколько и это решение.
4 ответа
ты можешь найти это
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, что является моим самым любимым способом сделать это.