Утечка памяти в действии вводит координатор перехода после перехода совместно используемого элемента

У меня проблема с утечкой памяти в EnterTransitionCoordinator при использовании общих переходов элементов. Ниже вы можете увидеть структуру приложения:

Имеет 2 экрана, первый Activity с DrawerLayout и мало Fragment внутри. Один из них состоит из списка фотографий и щелчка по конкретному фото запускает переход к общему элементу в Fragment от ViewPager находится в другом Activity, Я использую кастом SharedElementCallback при выходе и повторном входе в эти два Activity s для отображения правильного View для общего перехода элемента. Я основал свой код на этом замечательном сообщении в блоге: https://android.jlelse.eu/dynamic-shared-element-transition-23428f62a2af

Проблема в том, что после пролистывания между ViewPager предметы, Fragment S разрушаются, но View используется для перехода общего элемента хранится в Activity "s ActivityTransitionState конкретно в EnterTransitionCoordinator, То же самое при повторном входе в Activity с DrawerLayout а затем открывая другой Fragment, Ссылки на View s, используемые для переходов совместно используемых элементов, все еще хранятся в Activity с хотя Fragment s были уничтожены, что приводит к утечке памяти.

Мой вопрос: есть ли хороший способ избежать этой утечки памяти?

1 ответ

Я обнаружил, что есть метод clearState() в EnterTransitionCoordinator, который должен быть вызван в Activity.onStop(), Но так как Activity еще не остановлен, Viewс из Fragmentсливаются. В качестве временного решения я очищаю это состояние вручную 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)
    }
}
Другие вопросы по тегам