UIを表示するフラグメントに.setOnRetainInstance(true)
を設定すると、メモリリークが発生する可能性があることを読みました。
誰かがこれがなぜ、どのように起こるのか説明してもらえますか?詳細な説明はどこにも見つかりませんでした。
UIを備えたFragment
では、アクセスを高速化するために、いくつかのView
sをインスタンス状態として保存することがよくあります。たとえば、あなたのEditText
へのリンクですので、常にfindViewById
する必要はありません。
問題は、View
がActivity
コンテキストへの参照を保持していることです。 View
を保持すると、そのコンテキストへの参照も保持されます。
コンテキストがまだ有効な場合でも問題はありませんが、一般的な保持の場合はアクティビティを再起動します。非常に頻繁に画面の回転などのために。アクティビティを再作成すると、新しいコンテキストが作成され、古いコンテキストはガベージコレクションの対象になります。ただし、Fragment
にはまだ古いものへの参照があるため、ガベージコレクションできません。
次の例は、それをしない方法を示しています
public class LeakyFragment extends Fragment {
private View mLeak; // retained
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mLeak = inflater.inflate(R.layout.whatever, container, false);
return mLeak;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// not cleaning up.
}
}
その問題を取り除くには、onDestroyView
のUIへのすべての参照をクリアする必要があります。 Fragment
インスタンスが再利用されると、onCreateView
に新しいUIを作成するように求められます。 onDestroyView
の後にUIを保持する意味もありません。 Uiは使用されません。
この例の修正は、単にonDestroyView
を
@Override
public void onDestroyView() {
super.onDestroyView();
mLeak = null; // now cleaning up!
}
View
sへの参照を維持することに加えて、明らかにActivity
への参照を維持すべきではありません(たとえば、onAttach
から-onDetach
でクリーンアップ)またはContext
(Application
コンテキストでない限り)。
setRetainInstance(true)
は、画面の回転やその他の構成の変更など、アクティビティの再作成中に動的フラグメントのインスタンスを保持するために使用されます。これは、フラグメントがシステムによって永久に保持されることを意味しません。
ユーザーがアクティビティを終了するなど、他の理由でアクティビティが終了した場合(つまり、戻る)、フラグメントはガベージコレクションの対象になります。
アクティビティに結合されている特定のオブジェクトを保持する場合は注意してください。
注意:任意のオブジェクトを返すことができますが、Drawableなど、アクティビティに関連付けられているオブジェクトを渡さないでください、Adapter、View、またはコンテキストに関連付けられている他のオブジェクト。使用すると、元のアクティビティインスタンスのすべてのビューとリソースがリークします。 (リソースのリークとは、アプリケーションがリソースを保持し、ガベージコレクションできないため、大量のメモリが失われることを意味します。)
http://developer.Android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject
「setRetainInstance」は、アクティビティが再作成されるときにフラグメントの状態を維持するために使用されます。公式ドキュメントによると、「setRetainInstance」を使用すると、フラグメントのライフサイクルの2つのメソッド(onCreate、onDestroy)は実行されません。ただし、フラグメントに含まれるビューは再作成されます。これは、ライフサイクルが「onCreateView」から実行されるためです。これらの場合、「onSaveInstanceState」にデータを保存した場合、「onCreate」ではなく「onActivityCreated」でデータを要求する必要があります。
公式情報: https://developer.Android.com/reference/Android/app/Fragment.html#setRetainInstance(boolean)
詳細: https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/en