3

EnterTransitionCoordinator共有要素遷移の使用中にメモリ リークの問題が発生しました。以下に、アプリの構造を示します。

アプリの構造

2 つの画面があり、最初はActivitywithDrawerLayoutといくつかFragmentの s です。それらの 1 つは写真のリストで構成され、特定の写真をクリックすると、別のFragmentからへの共有要素遷移がトリガーされます。これら 2 つの s を終了して再入力するときにカスタムを使用して、共有要素の遷移を正しくマッピングしています。この素晴らしいブログ投稿に基づいてコードを作成しました: https://android.jlelse.eu/dynamic-shared-element-transition-23428f62a2afViewPagerActivitySharedElementCallbackActivityView

ViewPager問題は、のアイテム間をスワイプした後Fragment、 が破棄されているのに、View共有要素の遷移に使用されている がActivityActivityTransitionState、特に に保持されていることEnterTransitionCoordinatorです。Activitywithに再入力してからDrawerLayout別の を開く場合も同様Fragmentです。View共有要素の遷移に使用されるへの参照は、 が破棄されActivityても int のままFragmentであり、メモリ リークが発生します。

私の質問: このメモリ リークを回避する良い方法はありますか?

4

1 に答える 1

2

で呼び出す必要があるメソッドclearState()がにあることを発見しました。しかし、はまだ停止されていないため、からがリークされています。一時的な回避策として、このメソッドをリフレクションで呼び出すことにより、その状態を手動でクリアしています。以下にコードを示します。EnterTransitionCoordinatorActivity.onStop()ActivityViewFragmentFragment.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 に答える