¿Podría Navigation Arch Component crear una pérdida de memoria positiva falsa?

14

Tengo un conocimiento básico de las pérdidas de memoria y de lo que puede causarlas. Es por eso que no entiendo si tengo un problema en mi código o es un falso positivo. No sé qué parte del código debo compartir ya que el proyecto no es pequeño. Pero solo házmelo saber en los comentarios y agregaré el código requerido.

Uso el componente de arco de navegación y sigo el patrón MVVM. Agregué la biblioteca LeakCanary más adelante en el desarrollo del proyecto e inmediatamente comenzó a darme advertencias sobre instancias retenidas cuando navego entre pantallas.

El problema ocurre cuando agrego fragmentos a la pila posterior. Con cada fragmento agregado a la pila posterior, aumenta el contador de instancias retenidas. Cuando alcanza el valor umbral de 5, LeakCanary volca el montón y proporciona un informe.

Pero si hago clic en el botón Atrás y vuelvo a las pantallas anteriores, el contador de instancias retenidas disminuye y, finalmente, cuando se regresa a la primera pantalla, todas las instancias retenidas desaparecen.

Si miro los informes de análisis de montón, dice que se CoordinatorLayoutha filtrado la variable coordinatorLayout, que es una referencia a in xml. Si elimino la variable y todo su uso y ejecuto la aplicación nuevamente, veo el mismo problema, pero ahora con otra variable que es una referencia a otra vista en xml. Traté de eliminar todas las vistas y su uso que LeakCanary informó que se filtró. Cuando decía que a TextView, que solo se usa para establecer un texto onViewCreatedy no se usa en ningún otro lugar, está goteando, comencé a dudar de que haya un problema en mi código.

Analicé las llamadas al método del ciclo de vida en fragmentos y noté que cuando navego a una nueva pantalla para el fragmento anterior, todos los métodos hasta e inclusive onDestroyViewse llaman pero no onDestroy. Cuando hago clic en Atrás, onDestroyse solicita un fragmento que estaba encima de la pila de respaldo y el contador de instancias retenidas disminuye.

Sospecho que el componente de navegación mantiene la instancia de un fragmento cuando está en la pila trasera y LeakCanary lo ve como una fuga.

Marat
fuente

Respuestas:

24

Así es como funcionan los Fragmentos en la pila posterior (y Navigation solo usa las API de Fragmentos existentes): la vista del Fragmento se destruye, pero el Fragmento en sí no se destruye: se mantienen en el CREATEDestado hasta que presione el botón Atrás y regrese al Fragmento (después de lo cual se onCreateView()volverá a llamar y volverá a subir RESUMED).

Según los Fragmentos: charla Pasado, Presente y Futuro , uno de los cambios futuros que vienen a Fragmentos es una opción opcional para destruir Fragmentos en la pila posterior, en lugar de tener dos ciclos de vida separados. Esto aún no está disponible.

Debe anular sus referencias a las vistas, onDestroyViewya que esa es la señal de que el sistema Fragment ya no usa la vista y puede recolectarse basura de forma segura si no fuera por su referencia continua a la Vista.

ianhanniballake
fuente
2
¿Android View Binding soluciona este problema? No puedo encontrar ninguna documentación sobre si la referencia a las vistas de enlace de vista (tal vez el objeto de enlace en sí) se 'anula' automáticamente onDestroyViewcon el enlace de vista.
Tim Malseed
3
@TimMalseed: debe anular su referencia al objeto de enlace usted mismo, no hay nada automático.
ianhanniballake
1
@Emmanuel: debe soltar su referencia al objeto de enlace en sí, ya que contiene una referencia sólida a las Vistas que posee.
ianhanniballake
1
@Emmanuel: ¡siempre puede presentar una solicitud de función !
ianhanniballake
1
@Emmanuel: creo que sin duda sería un cambio en el comportamiento (lo que puede implicar que se trate de un indicador de suscripción independiente), pero tener el LifecycleOwner correcto sería suficiente información para solucionar una franja completa de problemas de memoria.
ianhanniballake