3

我在EnterTransitionCoordinator使用共享元素转换时遇到内存泄漏问题。您可以在下面看到应用程序结构:

应用结构

它有 2 个屏幕,第一个是一个ActivitywithDrawerLayout和几个Fragments 里面。其中一个包含照片列表,单击特定照片会触发共享元素FragmentViewPager位于另一个中的元素转换Activity。我SharedElementCallback在退出和重新输入这两个Activitys 时使用 custom 来映射正确View的共享元素转换。我的代码基于这篇很棒的博客文章:https ://android.jlelse.eu/dynamic-shared-element-transition-23428f62a2af

问题是,在ViewPager's 项目之间滑动后,Fragments 被销毁,但View用于共享元素转换的被保留在Activity'sActivityTransitionState中,特别是在EnterTransitionCoordinator. 重新进入到ActivitywithDrawerLayout然后打开另一个时也是如此Fragment。即使s 被销毁,View对用于共享元素转换的 s 的引用仍保留为 int s ,这会导致内存泄漏。ActivityFragment

我的问题:有没有避免这种内存泄漏的好方法?

4

1 回答 1

2

我发现有一个方法clearState()in EnterTransitionCoordinator,应该调用 in Activity.onStop()。但是由于sActivity尚未停止,因此Views 中的Fragments 正在泄漏。作为临时解决方法,我Fragment.onDestroyView()通过反射调用此方法手动清除该状态。您可以在下面看到代码:

/**
 * Works only for API < 28
 * https://developer.android.com/about/versions/pie/restrictions-non-sdk-interfaces
 */
fun Fragment.clearEnterTransitionState() {
    try {
        getActivityTransitionState()
            ?.getEnterTransitionCoordinator()
            ?.invokeClearStateMethod()
    } catch (e: Exception) {
        // no-op
    }
}

private fun Fragment.getActivityTransitionState() =
    Activity::class.java.getField("mActivityTransitionState", requireActivity())

private fun Any.getEnterTransitionCoordinator() = javaClass.getField("mEnterTransitionCoordinator", this)

private fun Any.invokeClearStateMethod() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        javaClass.superclass?.invokeClearStateMethod(this)
    } else {
        javaClass.invokeClearStateMethod(this)
    }
}

private fun <T> Class<T>.getField(name: String, target: Any): Any? =
    getDeclaredField(name).run {
        isAccessible = true
        get(target)
    }

private fun <T> Class<T>.invokeClearStateMethod(target: Any) {
    getDeclaredMethod("clearState").apply {
        isAccessible = true
        invoke(target)
    }
}
于 2018-12-22T21:13:40.380 回答