web-dev-qa-db-ja.com

UIおよびメモリリークを含む保持フラグメント

UIを表示するフラグメントに.setOnRetainInstance(true)を設定すると、メモリリークが発生する可能性があることを読みました。

誰かがこれがなぜ、どのように起こるのか説明してもらえますか?詳細な説明はどこにも見つかりませんでした。

30

UIを備えたFragmentでは、アクセスを高速化するために、いくつかのViewsをインスタンス状態として保存することがよくあります。たとえば、あなたのEditTextへのリンクですので、常にfindViewByIdする必要はありません。

問題は、ViewActivityコンテキストへの参照を保持していることです。 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!
}

Viewsへの参照を維持することに加えて、明らかにActivityへの参照を維持すべきではありません(たとえば、onAttachから-onDetachでクリーンアップ)またはContextApplicationコンテキストでない限り)。

87
zapl

setRetainInstance(true)は、画面の回転やその他の構成の変更など、アクティビティの再作成中に動的フラグメントのインスタンスを保持するために使用されます。これは、フラグメントがシステムによって永久に保持されることを意味しません。

ユーザーがアクティビティを終了するなど、他の理由でアクティビティが終了した場合(つまり、戻る)、フラグメントはガベージコレクションの対象になります。

3
wsanville

アクティビティに結合されている特定のオブジェクトを保持する場合は注意してください。

注意:任意のオブジェクトを返すことができますが、Drawableなど、アクティビティに関連付けられているオブジェクトを渡さないでください、AdapterView、またはコンテキストに関連付けられている他のオブジェクト。使用すると、元のアクティビティインスタンスのすべてのビューとリソースがリークします。 (リソースのリークとは、アプリケーションがリソースを保持し、ガベージコレクションできないため、大量のメモリが失われることを意味します。)

http://developer.Android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject

3
Emanuel Canha

「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

0
FacuArg