12

ナビゲーションタブ内でフラグメントが使用されている場合にフラグメントのビューステートを保持する方法を理解しようとしています。私の努力の中で、私は適切な解決策を見つけることができない2つの問題に遭遇しました。

Tab1とTab2の2つのタブがあります。Tab1のレイアウトはによって定義されFragmentA、Tab2のレイアウトはによって定義されFragmentBます。私はここで与えられたアプローチに従いました(編集:この質問がされてからドキュメントが変更されました)。

最初の問題:ビューにIDがありますが、フラグメントが再アタッチされたとき(タブスイッチの回転後)、ビューの状態が完全に復元されません。特にEditText、IDを持つan実際に入力されたテキストを保存しますが、有効なステータスは保存しません。また、IDがある場合でも、ボタンが有効または無効になっている場合、ボタンは保存されません。この問題に対して考えられる2つの回避策を見つけました。

  1. タブを切り替えるときにhide()/show()代わりに使用します。attach()/detach()
  2. で、を介してフラグメントのインスタンス変数にonPause()現在のフラグメントビューステートを保存します。このフィールドがnullでないかどうかを確認し、そうである場合は、このフィールドの値を返します。この解決策はハッキーなようで、アプリにメモリリークが発生する可能性があると言われています。ViewgetView()onCreateView(Bundle savedInstanceState)

2番目の問題:次のユーザーインタラクションを検討してください。ユーザーはTab1から開始し、Tab1のビューステートをデフォルトの状態とは異なる状態にするいくつかの変更を行います(フラグメントがタブスイッチとデバイスの傾きによってこのビューステートを保存するようにします) 。次に、ユーザーはTab2に移動します。次に、ユーザーは自分のデバイスを傾けます(まだTab2にあります)。次に、ユーザーはTab1に切り替えます(新しい画面の向きで)。ここで、問題は次のとおりです。ユーザーが最初にTab1からTab2にスワップすると、フラグメントが切り離され、その結果、ビューが破棄されます(フラグメントインスタンスはまだ存在していますが)。次にユーザーがデバイスを傾けると、アクティビティ(およびそれによって両方FragmentAとそれにFragmentB関連付けられている)が破棄されます。以来FragmentAこの時点でビューはなくなり(デタッチされたことを思い出してください)、への呼び出し中にビュー要素の状態(たとえば、どのボタンが有効/無効になっているか)を保存できませんFragmentA.onSaveInstanceState(Bundle savedInstanceState)。このような状況でフラグメントビューの状態をどのように回復しますか?すべての単一のビュー要素の異なるステータスフラグをSharedPreferencesとして保存する唯一の実行可能なソリューションはありますか?これは、このような「日常の仕事」には複雑すぎるようです。

4

2 に答える 2

8

問題 1:

デフォルトでは、Android はビューが有効な状態を保存しません。ユーザーの操作によって (追加のコードなしで) 直接影響を受けるものだけが保存されるようです。通常のビューの場合、情報は保存されず、EditText がサブクラスである TextView の場合、入力されたテキストが保存されます( freezesTextが設定されている場合)。

他に救いたいことがあれば、自分でやらなければなりません。これは、カスタム ビュー ステートの保存を実装する方法を示すいくつかの回答を含む質問です。そのアプローチに従えば、アタッチ/デタッチに固執することができます。

問題 2:

ビューが既に破棄された後に Fragment.onSaveInstanceState(Bundle) を呼び出すことができるということは正しいです。ただし、これはビュー ステートを保存する場所ではありません。Android は、フラグメントをデタッチするときにビューを破棄する直前に View.onSaveInstanceState() を呼び出します。この状態を保存し、フラグメントを再度アタッチすると元に戻ります。これは、通常、回転せずにタブ間をめくったときに起こることです。デタッチ時に Fragment.onSaveInstanceState(Bundle) は呼び出されません。デバイスを回転させても、デタッチの結果として保存されたビュー ステートは保持されます。上記のように View.onSaveInstanceState() を実装すると、Tab1-Tab2-rotate-Tab1 シナリオでも、ビュー ステートが適切に保存および復元されます。

補足:ドキュメント のサンプル コードは、回転しようとすると問題があるようです。TabListener の存続期間は Activity の存続期間と同じです。回転するたびに新しいものが作成されます。これは、回転するたびに、フラグメントへの内部参照も失われることを意味します。追加されたフラグメントは自動的に再作成されるため、ローテーション後に TabListener が新しいインスタンスを作成して追加しようとする必要はありません。内部参照の代わりに、フラグメント マネージャーで適切なタグを持つフラグメントを見つけようとするだけです。回転後も存在します。

もう 1 つの問題は、選択したタブが保存されないことですが、これは例の下部に記載されています。これを Activity.onSaveInstanceState(Bundle) に保存できます。

于 2013-03-16T17:50:20.990 に答える
0
private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // on tab selected
    // show respected fragment view
    viewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
于 2014-12-09T13:49:05.910 に答える