Утечка памяти в действии вводит координатор перехода после перехода совместно используемого элемента
У меня проблема с утечкой памяти в 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)
}
}