メモリリークとその原因についての基本的な知識があります。そのため、コードに問題があるのか、それとも誤検知なのかわかりません。プロジェクトは小さくないので、コードのどの部分を共有するべきかわかりません。ただし、コメント欄でお知らせください。必要なコードを追加します。
ナビゲーションArchコンポーネントを使用し、MVVMパターンに従います。プロジェクトの開発の後半でLeakCanaryライブラリを追加したところ、画面間を移動すると、保持されたインスタンスに関する警告がすぐに表示され始めました。
この問題は、バックスタックにフラグメントを追加すると発生します。バックスタックにフラグメントを追加するたびに、保持されるインスタンスのカウンターが増加します。 LeakCanaryがしきい値の5に達すると、ヒープがダンプされ、レポートが提供されます。
しかし、[戻る]ボタンをクリックして前の画面に戻ると、保持されているインスタンスのカウンターが減少し、最終的に1番目の画面に戻ると、保持されているすべてのインスタンスが消えます。
ヒープ分析レポートを見ると、xmlのCoordinatorLayout
への参照である変数coordinatorLayoutがリークしていることがわかります。変数とそのすべての使用法を削除してアプリを再度実行すると、同じ問題が発生しますが、別の変数がxml内の別のビューへの参照になっています。 LeakCanaryがリークしていると報告したすべてのビューとその使用法を削除しようとしました。 TextView
にテキストを設定するためだけに使用され、他では使用されないonViewCreated
がリークしていると言われたとき、コードに問題があることに疑問を感じ始めました。
ライフサイクルメソッドの呼び出しをフラグメントで分析したところ、前のフラグメントの新しい画面に移動すると、onDestroyView
までのすべてのメソッドが呼び出されますが、onDestroy
は呼び出されません。戻るをクリックすると、バックスタックの上にあったフラグメントに対してonDestroy
が呼び出され、保持されているインスタンスのカウンターが減少します。
ナビゲーションコンポーネントがフラグメントがバックスタックにあるときにフラグメントのインスタンスを保持しており、LeakCanaryがそれをリークとして認識していると思います。
これが、バックスタックのフラグメントが機能する方法です(ナビゲーションは既存のフラグメントAPIを使用するだけです)。フラグメントのビューは破棄されますが、フラグメント自体は破棄されません。それらは、バックを押すまでCREATED
状態に保持されますボタンをクリックしてフラグメントに戻ります(その後、onCreateView()
が再度呼び出され、RESUMED
に戻ります)。
フラグメント:過去、現在、および未来の話 のとおり、フラグメントにもたらされる将来の変更の1つは、2つの個別のライフサイクルではなく、バックスタック上のフラグメントを破棄するオプトインオプションです。これはまだ利用できません。
onDestroyView
のビューへの参照をnullにする必要があります。これは、ビューがフラグメントシステムで使用されなくなったことを示しており、継続的な参照がなければ、ガベージコレクションを安全に実行できます。景色。