3

私はViewPagerにある必要がある3つの断片があります。これらのフラグメントは、データベースから取得した動的情報を保持します。私はオリエンテーションの変更で、活動と断片が破壊され再作成されることを理解しています。しかし、私はFragmentStatePagerAdapterがフラグメントの状態を保存するという名前の印象の下にいました。どうやら、私はフラグメントに何かをした後、向きを変えるたびにフラグメントがレイアウトxmlファイルにどのようにレイアウトされたかに戻ってしまうので間違っていました。FragmentStatePagerAdapterは方向変更にフラグメント状態を保存しますか?

私がデバッグしていたとき、向きの変更でアダプタのgetItem()メソッドが呼び出されなかったことがわかりました。つまり、再作成されませんでした。だから、どのように元の状態に戻ってフラグメントの状態に戻って来る?

FragmentStatePagerAdapterを使用してフラグメントの状態を保存するにはどうすればよいですか?

私はこのtutorialに従っており、SmartFragmentStatePagerAdapter.javaクラスのバージョンを使用して断片を動的に管理しています。

これは私のサンプルコードです。

PageLoader.java - このインターフェイスにより、MainActivityは実行時にフラグメントページのロードを動的に管理できます。

public interface PageLoader { 
    void loadPage(int from, int target); 
} 

MainActivity.java

public class MainActivity extends AppCompatActivity implements PageLoader { 
    MyPagerAdapter adapter; 
    DirectionalViewPager pager; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     // Get the ViewPager and set it's PagerAdapter so that it can display items 
     pager = (DirectionalViewPager) findViewById(R.id.vpPager); 
     adapter = new MyPagerAdapter(getSupportFragmentManager()); 
     pager.setOffscreenPageLimit(5); 
     pager.setAdapter(adapter); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int position = pager.getCurrentItem(); 
     if (position > 0) pager.setCurrentItem(position - 1); 
     return true; 
    } 

    @Override 
    public void loadPage(int from, int target) { 
     PageLoader fragment = (PageLoader) adapter.getRegisteredFragment(target); 
     fragment.loadPage(from, target); 
    } 
} 

MyPagerAdapter.java

public class MyPagerAdapter extends SmartFragmentStatePagerAdapter { 
    private static final int NUM_ITEMS = 4; 

    public MyPagerAdapter(FragmentManager fragmentManager) { 
     super(fragmentManager); 
    } 

    // Returns total number of pages 
    @Override 
    public int getCount() { 
     return NUM_ITEMS; 
    } 

    // Returns the fragment to display for that page 
    @Override 
    public Fragment getItem(int position) { 
     switch (position) { 
      case 0: // Fragment # 0 - This will show Frag1 
       return Frag1.newInstance(position, Frag1.class.getSimpleName()); 
      case 1: // Fragment # 0 - This will show Frag1 different title 
       return Frag1.newInstance(position, Frag1.class.getSimpleName()); 
      case 2: // Fragment # 1 - This will show Frag2 
       return Frag2.newInstance(position, Frag2.class.getSimpleName()); 
      default: 
       return Frag3.newInstance(position, Frag3.class.getSimpleName()); 
     } 
    } 

    // Returns the page title for the top indicator 
    @Override 
    public CharSequence getPageTitle(int position) { 
     return "Page " + position; 

    } 
} 

Frag1.javaFrag2.javaFrag3.java - 番号付け以外はすべて同じです。

public class Frag1 extends Fragment implements PageLoader { 
    // Store instance variables 
    private String title; 
    private int page; 
    private TextView txtView; 

    // newInstance constructor for creating fragment with arguments 
    public static Frag1 newInstance(int page, String title) { 
     Frag1 fragmentFirst = new Frag1(); 
     Bundle args = new Bundle(); 
     args.putInt("someInt", page); 
     args.putString("someTitle", title); 
     fragmentFirst.setArguments(args); 
     return fragmentFirst; 
    } 

    // Store instance variables based on arguments passed 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     page = getArguments().getInt("someInt", 0); 
     title = getArguments().getString("someTitle"); 
    } 

    // Inflate the view for the fragment based on layout XML 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.frag1, container, false); 
     txtView = (TextView) view.findViewById(R.id.txt_frag1); 
     txtView.setText(page + " - " + title); 

     Button btn = (Button) view.findViewById(R.id.btn_frag1); 
     btn.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       PageLoader activity = (PageLoader) getActivity(); 
       activity.loadPage(page, page+1); 

      } 
     }); 
     return view; 
    } 

    @Override 
    public void loadPage(int from, int target) { 
     txtView.setText(txtView.getText() + "\nThis message was created from" + from + " to " + target); 
    } 
} 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <com.example.someone.smartfragmentstatepageradapter.custom.DirectionalViewPager 
     android:id="@+id/vpPager" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

    </com.example.someone.smartfragmentstatepageradapter.custom.DirectionalViewPager> 
</LinearLayout> 

frag1.xmlfrag2.xmlfrag3.xml - 再び、これらは番号

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" 
    android:background="#cc2"> 

    <TextView 
     android:id="@+id/txt_frag1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:text="txt_frag1" 
     /> 
    <Button 
     android:id="@+id/btn_frag1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:text="btn_frag1" 
     android:textSize="26dp" /> 

</LinearLayout> 
以外はすべて同じです

PLEAS Eは、フラグメントの「状態」を保存するためにFragmentStatePagerAdapterを使用する方法を教えてくれます。私は今日、午前9時から午後9時までインターネットを掃除しています... 12時間...私は本当にこれを理解する助けが必要です。前もって感謝します!

答えて

2

EDITはこれを試してみてください:

は、あなたのフラグメントに別のインスタンス変数を追加します。

loadPageでこの変数を設定し
private String text; // this is part of saved state 

:この変数を保存する

@Override 
    public void loadPage(int from, int target) { 
     text = txtView.getText().toString() + "\nThis message was created from" + from + " to " + target; 
     txtView.setText(text); 
    } 

オーバーライドonSaveInstanceState

@Override 
    public void onSaveInstanceState(Bundle outState); 

     outState.putString("text", text); 
     super.onSaveInstanceState(outState); 
    } 

は、この変数を使用してTextView状態を復元:

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 

     if (savedInstanceState != null) { 
      // not null means we are restoring the fragment 
      text = savedInstanceState.getString("text"); 
     } else { 
      text = "" + page + " - " + title; 
     } 
     View view = inflater.inflate(R.layout.frag1, container, false); 
     txtView = (TextView) view.findViewById(R.id.txt_frag1); 
     txtView.setText(text); 

     Button btn = (Button) view.findViewById(R.id.btn_frag1); 
     btn.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       PageLoader activity = (PageLoader) getActivity(); 
       activity.loadPage(page, page+1); 

      } 
     }); 
     return view; 
    } 

設定変更のようなものが発生したとき、あなたのフラグメントの中で何かが同じに滞在したい任意の時間は、これはあなたが保存し、状態を追跡する方法をありますそれを復元します。


あなたが断片や活動のためのonSaveInstanceStateを使用する場所です。

これは、必要な状態を保存するために上書きする方法です。フラグメント内で変更して、構成変更で再作成したいものは、onCreateまたはonCreateViewの間に保存して復元する必要があります。

あなたはloadPageで作成したテキストを復元しようとしているのであれば、あなたは、テキストのためのクラスレベルの文字列を作成loadPageでそれを設定し、onSaveInstanceStateオーバーライドでそれを保存し、その後からonCreateViewにで復元しますsavedInstanceStateパラメータ。

ここにキッカーがあります:設定変更後にアダプタのgetItemが呼び出されていないことに気づいています。しかし、あなたはあなたの断片がまだそこにあることに気が付きましたか?アクティビティには、フラグメントとそのトランザクションを管理しているFragmentManagerがあることに注意してください。アクティビティがコンフィグレーション変更に進むと、その状態が保存されます。 FragmentManagerとすべてのアクティブなフラグメントは、その状態の一部です。その後、フラグメントは、adapter.getItemが呼び出されないように復元されます。

それは、SmartFragmentPagerAdapterがあまりスマートではないことが分かります。設定変更後にはregisteredFragmentsアレイを再作成することはできませんので、あまり有用ではありません。私はそれを使用することをお勧めしません。

ViewPagerが独自の目的でフラグメントのタグを割り当てた場合、どのようにイベントをオフページフラグメントに送信しますか?

私が使用する手法は、イベントリスナーインターフェイスを定義し、そのフラグメントをアクティビティのリスナーとして登録することです。イベントを発生させるときは、アクティブなリスナーに通知するアクティビティのメソッドを呼び出します。私はこれの完全な例をthis answerに挙げています。

+0

"FragmentManagerとすべてのアクティブなフラグメントは、その状態の一部です。フラグメントは、adapter.getItemが呼び出されないように復元されます。 - このビットを明確にすることはできますか?すべてのアクティブなフラグメントがその状態の一部である場合、なぜそのフラグメントの状態がアクティビティとともに復元されないのでしょうか? – chaser

+0

これをさらに読む:https:// inthecheesefactory。com/blog/fragment-state-saving-best-practices/en - 私は引用しています "しかし、Fragmentのライフサイクルによって新たに作成されたビューは、上記のように何が起こったのですか?問題ありません。この場合内部的にはフラグメントの内部と呼ばれます。だから彼らは、フラグメント内のすべてのビューは、独自の状態を復元する能力を持っている必要があると言っている...明らかに、フラグメントがViewPagerにある場合ではない?私は本当に失われています。 – chaser

+0

私の更新された答えを見てください。前述したように、セーブ/リストアは内部的に呼び出されますが、*あなたはまだフラグメントに何を保存して復元するかを伝える必要があります*。それらはフレームワークを提供しますが、状態を追跡し、保存してから、保存された状態を使用してビューを再作成するという重い作業をすべてやり直さなければなりません。うまくいけば、私のコード例でこれを実証することができます。 –

関連する問題