Простой способ получить текущую активность, фрагмент, 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, что является моим самым любимым способом сделать это.

Другие вопросы по тегам