如何使自定义视图观察到包含片段的生命周期事件而不是活动?

时间:2018-10-31 23:42:50

标签: android android-fragments android-lifecycle

我有一个活动以及在框架布局中替换的几个片段。每个片段都包含从XML扩展的布局,并带有许多自定义视图。在这些视图中,我想使用LifecycleObserver在这些视图中订阅生命周期事件。我在科特林的观点:

class MyView(context: Context) : View(context, null, 0): LifecycleObserver {

    init {
        (getContext() as LifecycleOwner).lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        // code
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        // code
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        lifecycle.removeObserver(this)
    }

}

问题是,当一个片段消失并被另一个片段替换时,第一个片段中的视图不会收到 onPause 事件。当我从第二个片段返回时,它们也不会得到 onResume 。仅当整个活动暂停时,视图才会收到 onPause ,但它们不了解片段中生命周期的变化。我将其跟踪到布局填充器,该布局填充器用于填充片段的xml布局,它将活动作为 context 参数传递给视图。这是在支持库的Fragment类中实例化布局充气器的方式:

/** @deprecated */
@Deprecated
@NonNull
@RestrictTo({Scope.LIBRARY_GROUP})
public LayoutInflater getLayoutInflater(@Nullable Bundle savedFragmentState) {
    if (this.mHost == null) {
        throw new IllegalStateException("onGetLayoutInflater() cannot be executed until the Fragment is attached to the FragmentManager.");
    } else {
        LayoutInflater result = this.mHost.onGetLayoutInflater();
        this.getChildFragmentManager();
        LayoutInflaterCompat.setFactory2(result, this.mChildFragmentManager.getLayoutInflaterFactory());
        return result;
    }
}

mHost 是包含此片段的FragmentActivity。因此,传递到片段的onCreateView()中的LayoutInflater包含对FragmentActivity的引用作为上下文。因此,视图有效地观察了Activity的生命周期。

如何让我的自定义视图观察其包含片段的生命周期事件?

1 个答案:

答案 0 :(得分:1)

如果仅使用onPause()onResume(),则在View类中覆盖onDetachedFromWindow()onAttachedToWindow()就足够了:

override fun onAttachedToWindow() {
    //onResume code
}

override fun onDetachedFromWindow() {
    //onPause code
}

您还可以创建自己的生命周期方法:

fun onResume() {}
fun onPause() {}

您可以在片段中保留对视图的全局引用:

//`by lazy` only initializes the variable when it's fist called, 
//and then that instance is used for subsequent calls. 
//Make sure you only reference `myView` after `onCreateView()` returns
private val myView by lazy { view.findViewById<MyView>(R.id.my_view) }

然后从您的Fragment的onPause()onResume()中,调用View的相应方法:

override fun onPause() {
    myView.onPause()
}

override fun onResume() {
    myView.onResume()
}

编辑:

要获得可扩展性,请制作自己的min-SDK。创建一个基本的Fragment类:

open class LifecycleFragment : Fragment() {
    internal fun dispatchOnResume(parent: View) {
        if (parent is CustomLifecycleObserver) parent.onResume()
        if (parent is ViewGroup) {
            for (i in 0 until parent.childCount) {
                dispatchOnResume(parent.getChildAt(i))
            }
        }
    }

    internal fun dispatchOnPause(parent: View) {
        if (parent is CustomLifecycleObserver) parent.onPause()
        if (parent is ViewGroup) {
            for (i in 0 until parent.childCount) {
                dispatchOnResume(parent.getChildAt(i))
            }
        }
    }

    override fun onResume() {
        dispatchOnResume(view)
    }

    override fun onPause() {
        dispatchOnPause(view)
    }
}

({CustomLifecycleListener将是您的视图要实现的接口,包含onResume()onPause()方法。)

然后在您的其他片段中扩展该类:

class SomeFragment : LifecycleFragment() {}