Blcknx
Blcknx

Reputation: 2431

Easy way to get current Activity, Fragment, LifeCycleOwner from within View?

When writing Views, ViewModels and LiveData are lifecycle aware. The ViewModel want's the current FragmentActivity, LiveData the current LifecycleOwner. You don't know in advance if your View will be wrapped or somewhat. So it requires a flexible function to to find the wanted context. I ended up with this two methods:

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;
}

Now this is a lot of boilerplate code to put into each View. Is there a more easy way?

I don't want to use a customised View base class for this, as large hierarchy's are ugly. Composition on the other hand requires as much code as this solution.

Upvotes: 24

Views: 29205

Answers (4)

Ahmadreza Moodi
Ahmadreza Moodi

Reputation: 533

you can find it lifecycle-runtime-ktx :

fun View.findViewTreeLifecycleOwner(): LifecycleOwner? = ViewTreeLifecycleOwner.get(this)

Upvotes: 27

jc12
jc12

Reputation: 1829

Similar to another answer, but without needing to specify 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
    }

Upvotes: 2

Abhinav Atul
Abhinav Atul

Reputation: 629

Kotlin Extensions

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
    }
}

Usage

val lifecycleOwner = context.lifecycleOwner()
val fragmentActivity = context.fragmentActivity()

Upvotes: 6

Michał Powłoka
Michał Powłoka

Reputation: 1511

If you don't want to use composition you can put this into common BaseView class. Alternatively, you can make it a static method in some utils class.

If you use Kotlin you can also make it Kotlin extension function, what is my most favourite way of doing that.

Upvotes: 0

Related Questions