2013-03-16 9 views
12

ナビゲーションタブ内でフラグメントを使用すると、フラグメントビューの状態を保持する方法を理解しようとしています。私の努力の中で、私は適切な解決策を見つけることができない2つの問題に出くわしました。Androidのナビゲーションタブ:フラグメントビューの状態を復元する

私は2つのタブ、Tab1とTab2を持っています。 Tab1のレイアウトはFragmentAで定義され、Tab2のレイアウトはFragmentBで定義されます。 Adding navigation tabs

最初の問題: 私はここに与えられたアプローチに続いてきた私の見解は、IDを持っているにもかかわらずを断片が再装着された場合には、それらの状態は完全に(タブの切り替え回転後)に復元されていません。具体的には、IDを持つEditTextは実際に入力されたテキストを保存しますが、有効なステータスは保存されません。また、私のボタンは、IDを持っていても有効または無効にすると保存されません。タブを切り替えるhide()/show()代わりのattach()/detach()

  1. 用途:私はこの問題の2つの回避策を見つけました。
  2. onPause()getView()でフラグメントのインスタンス変数Viewに現在のフラグメントビューの状態を保存します。 onCreateView(Bundle savedInstanceState)でこのフィールドがnullでないかどうかをチェックし、そうである場合はこのフィールドの値を返します。このソリューションはハックのようだ、私はそれも私のアプリでメモリリークを導入するかもしれないと言われてきた。

第二の問題:には、次のユーザーとの対話を考えてみましょう: ユーザーはTab1を上起動し、デフォルトの状態とは異なる状態にTab1をのビューステートを入れていくつかの変更を行います(と私たちは、フラグメントが保存したいですタブスイッチとデバイスの傾きによるこのビューの状態)。 ユーザーはTab2に行きます。ユーザーは彼女/彼のデバイスを傾けます(まだTab2にあります)。 その後、ユーザーはTab1(新しい画面方向)にスワップします。 問題は次のとおりです。ユーザーが最初にTab1からTab2にスワップすると、フラグメントがデタッチされ、そのビューが破棄されます(ただし、フラグメントインスタンスはまだ存続しています)。ユーザーがデバイスを傾けると、アクティビティー、それに関連付けられたFragmentAとFragmentBの両方が破棄されます。この時点でのFragmentAはビューをもはや持たないので(それはデタッチされていたことを覚えておいてください)、FragmentA.onSaveInstanceState(Bundle savedInstanceState)への呼び出し中に、ビュー要素の状態(例えば、どのボタンが有効/無効)を保存できません。このような状況でフラグメントビューの状態をどのように回復しますか?すべての単一のビュー要素の異なるステータスフラグをSharedPreferencesとして保存する唯一の実行可能なソリューションですか?このような「日常の仕事」では、これはあまりにも複雑なようです。

私はSOやさまざまなブログの記事を読んできましたが、この(特定の)問題の解決策を見つけることができませんでした。

答えて

7

問題1:

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

他のものを保存したい場合は、自分で行う必要があります。 Hereは、カスタムビューの状態保存を実装する方法を示すいくつかの回答がある質問です。あなたがそのアプローチに従うならば、あなたはアタッチ/デタッチをすることができます。

問題2:

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

サイドノート: ドキュメント内のexample codeには、回転しようとするといくつかの問題があるようです。 TabListenerの有効期間はアクティビティの有効期間と同じです。回転するたびに新しいものが作成されます。つまり、回転するたびにフラグメントの内部参照も失われます。追加されたフラグメントは自動的に再作成されるので、回転後にTabListenerが新しいインスタンスを作成して追加する必要はありません。代わりに、内部参照のうち、フラグメントマネージャで適切なタグを持つフラグメントを見つけようとするべきです。回転後もまだ存在します。

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

+0

多くのありがとう - 良い説明。しかし、事はまだ私には完全にはっきりしていません。私はあなたが指している答えを見てきましたが、私はその使い方を理解できませんでした。 「CustomView」とは何ですか?私のフラグメントビューの状態は、(EditTexts、Buttonsなどの)ビューのみで構成されています。したがって、私はViewクラスを拡張していません - 私は単にxmlレイアウトファイル内にフラグメントビューを構築しました。回答に提供されたサンプルコードを、ユーザー定義のビューを使用しないレイアウトに接続するにはどうすればいいですか?(CustomViewはアンドロイドにユーザー定義のコントロールをASP .NETとすると仮定します) –

+1

@jvmk View.onSaveInstanceState()を使用するには、Viewをサブクラス化してそのメソッドをオーバーライドする必要があります。レイアウトXMLは、EditText/Buttonではなく、これらの新しいビューを参照する必要があります。 – antonyt

+2

うわー、それは気違いです。ビューに組み込まれたビューの状態を復元することは、これが標準機能としてサポートされるのに十分頻繁に再発するタスクであると考えました。将来の使用のためにライブラリを書く必要があるとします。ここで私を助けてくれてありがとう。これは今、2週間私に迷惑をかける。 –

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) { 
} 
+1

単にコードを投稿するのではなく、あなたの答えに関するいくつかの情報を含めることを検討してください。私たちは単に「修正」だけでなく、人々が学ぶのを手助けするよう努めています。元のコードに何が間違っていたのか、何をどうやってやったのか、なぜ変更が働いたのかを説明する必要があります。 –

関連する問題