web-dev-qa-db-ja.com

ViewPagerとフラグメント - フラグメントの状態を保存する正しい方法は何ですか?

フラグメントは、UIロジックをいくつかのモジュールに分けるのにとてもいいようです。しかし、ViewPagerと共に、そのライフサイクルはまだ私にとって霧です。だから教祖の考えはひどく必要です!

編集する

下のダム解決策を見てください;-)

範囲

メインアクティビティには、フラグメントを含むViewPagerがあります。これらのフラグメントは他の(サブメイン)アクティビティに対して少し異なるロジックを実装することができるので、フラグメントのデータはアクティビティ内のコールバックインタフェースを介して埋められます。そして最初の起動ではすべてうまくいきますが、... ...

問題

アクティビティが再作成されたとき(たとえば向きの変更時)、ViewPagerのフラグメントも再作成されます。コード(後述)では、アクティビティが作成されるたびに、フラグメントと同じViewPagerフラグメントアダプタを作成しようとします(おそらく問題です)が、FragmentManagerには既にこれらのフラグメントすべてがどこかに格納されています。そしてそれらのためのレクリエーションメカニズムを開始します。そこで、再現メカニズムはActivityの実装されたメソッドを介してデータを開始するために私のコールバックインタフェース呼び出しで "古い"フラグメントのonAttach、onCreateViewなどを呼び出します。しかし、このメソッドはActivityのonCreateメソッドによって作成された新しく作成されたフラグメントを指しています。

問題

たぶん、私は間違ったパターンを使っていますが、Android 3 Proの本でさえそれについて多くのことを持っていません。それで、 お願い 、1 - 2パンチを与えて、それを正しい方法で行う方法を指摘してください。どうもありがとう!

コード

主な活動

public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {

private MessagesFragment mMessagesFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Logger.d("Dash onCreate");
    super.onCreate(savedInstanceState);

    setContentView(R.layout.viewpager_container);
    new DefaultToolbar(this);

    // create fragments to use
    mMessagesFragment = new MessagesFragment();
    mStreamsFragment = new StreamsFragment();

    // set titles and fragments for view pager
    Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();
    screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());
    screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);

    // instantiate view pager via adapter
    mPager = (ViewPager) findViewById(R.id.viewpager_pager);
    mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());
    mPager.setAdapter(mPagerAdapter);

    // set title indicator
    TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);
    indicator.setViewPager(mPager, 1);

}

/* set of fragments callback interface implementations */

@Override
public void onMessageInitialisation() {

    Logger.d("Dash onMessageInitialisation");
    if (mMessagesFragment != null)
        mMessagesFragment.loadLastMessages();
}

@Override
public void onMessageSelected(Message selectedMessage) {

    Intent intent = new Intent(this, StreamActivity.class);
    intent.putExtra(Message.class.getName(), selectedMessage);
    startActivity(intent);
}

BasePagerActivity別名ヘルパー

public class BasePagerActivity extends FragmentActivity {

BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}

アダプタ

public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {

private Map<String, Fragment> mScreens;

public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) {

    super(fm);
    this.mScreens = screenMap;
}

@Override
public Fragment getItem(int position) {

    return mScreens.values().toArray(new Fragment[mScreens.size()])[position];
}

@Override
public int getCount() {

    return mScreens.size();
}

@Override
public String getTitle(int position) {

    return mScreens.keySet().toArray(new String[mScreens.size()])[position];
}

// hack. we don't want to destroy our fragments and re-initiate them after
@Override
public void destroyItem(View container, int position, Object object) {

    // TODO Auto-generated method stub
}

}

フラグメント

public class MessagesFragment extends ListFragment {

private boolean mIsLastMessages;

private List<Message> mMessagesList;
private MessageArrayAdapter mAdapter;

private LoadMessagesTask mLoadMessagesTask;
private OnMessageListActionListener mListener;

// define callback interface
public interface OnMessageListActionListener {
    public void onMessageInitialisation();
    public void onMessageSelected(Message selectedMessage);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    // setting callback
    mListener = (OnMessageListActionListener) activity;
    mIsLastMessages = activity instanceof DashboardActivity;

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    inflater.inflate(R.layout.fragment_listview, container);
    mProgressView = inflater.inflate(R.layout.listrow_progress, null);
    mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);
    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // instantiate loading task
    mLoadMessagesTask = new LoadMessagesTask();

    // instantiate list of messages
    mMessagesList = new ArrayList<Message>();
    mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);
    setListAdapter(mAdapter);
}

@Override
public void onResume() {
    mListener.onMessageInitialisation();
    super.onResume();
}

public void onListItemClick(ListView l, View v, int position, long id) {
    Message selectedMessage = (Message) getListAdapter().getItem(position);
    mListener.onMessageSelected(selectedMessage);
    super.onListItemClick(l, v, position, id);
}

/* public methods to load messages from Host acitivity, etc... */
}

溶液

愚かな解決策は、putFragmentを使用して(Host Activityの)onSaveInstanceState内にフラグメントを保存し、getFragmentを介してonCreate内にそれらを取得することです。しかし、私はまだ物事がそのように機能するべきではないという奇妙な感じをしています...下記のコードを参照してください。

    @Override
protected void onSaveInstanceState(Bundle outState) {

    super.onSaveInstanceState(outState);
    getSupportFragmentManager()
            .putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);
}

protected void onCreate(Bundle savedInstanceState) {
    Logger.d("Dash onCreate");
    super.onCreate(savedInstanceState);

    ...
    // create fragments to use
    if (savedInstanceState != null) {
        mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment(
                savedInstanceState, MessagesFragment.class.getName());
                StreamsFragment.class.getName());
    }
    if (mMessagesFragment == null)
        mMessagesFragment = new MessagesFragment();
    ...
}
473

FragmentPagerAdapterがFragmentManagerにフラグメントを追加するとき、それはフラグメントが配置される特定の位置に基づく特別なタグを使います。 FragmentPagerAdapter.getItem(int position)は、その位置のフラグメントが存在しない場合にのみ呼び出されます。回転させると、Androidはこの特定の位置のフラグメントを既に作成/保存していることに気付くので、新しいフラグメントを作成するのではなく、単にFragmentManager.findFragmentByTag()を使用してそれと再接続しようとします。 FragmentPagerAdapterを使用すると、これらすべてが無料になります。フラグメント初期化コードをgetItem(int)メソッド内に含めるのが一般的な理由です。

FragmentPagerAdapterを使用していなくても、Activity.onCreate(Bundle)で毎回新しいフラグメントを作成するのはお勧めできません。お気づきのように、フラグメントがFragmentManagerに追加されると、回転した後にフラグメントが再作成され、再度追加する必要はありません。フラグメントを扱うときにそうするのがエラーの一般的な原因です。

フラグメントを扱うときの通常のアプローチはこれです。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    CustomFragment fragment;
    if (savedInstanceState != null) {
        fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag");
    } else {
        fragment = new CustomFragment();
        getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit(); 
    }

    ...

}

FragmentPagerAdapterを使用する場合は、フラグメント管理をアダプタに委ねるため、上記の手順を実行する必要はありません。デフォルトでは、現在位置の前後に1つのFragmentしかプリロードされません(ただし、FragmentStatePagerAdapterを使用していない限り、それらは破棄されません)。これは ViewPager.setOffscreenPageLimit(int) によって制御されます。このため、アダプタの外部でフラグメントのメソッドを直接呼び出すことは有効であるとは限りません。これらは有効でない可能性さえあります。

長い話を簡単にすると、後で参照を取得できるようにputFragmentを使用するという解決策はそれほど面倒ではなく、(上記の)フラグメントを使用する通常の方法とは異なります。フラグメントはアダプタによって追加され、個人的には追加されないため、それ以外の場合は参照を取得するのは困難です。 offscreenPageLimitが常に必要なフラグメントをロードするのに十分な大きさであることを確認してください。これはViewPagerの遅延ロード機能を迂回しますが、あなたのアプリケーションに望むもののようです。

もう1つの方法は、FragmentPageAdapter.instantiateItem(View, int)をオーバーライドして、スーパーコールから返されるフラグメントへの参照を返す前にそれを保存することです(既に存在する場合は、フラグメントを見つけるためのロジックがあります)。

より完全な図については、 FragmentPagerAdapter (short)および ViewPager (long)のソースを見てください。

441
antonyt

antonytwonderful answer を拡張するソリューションを提供し、作成したFragmentsへの参照を保存するためにFragmentPageAdapter.instantiateItem(View, int)をオーバーライドすることについて言及したい後でそれらに取り組むことができます。これはFragmentStatePagerAdapterでも機能するはずです。詳細については、注を参照してください。


以下は、Fragmentsに設定された内部FragmentPagerAdapterに依存しない、tagsによって返されるFragmentsへの参照を取得する方法の簡単な例です。重要なのは、 instantiateItem() をオーバーライドして、そこに参照を保存することです代わりにgetItem()で。

public class SomeActivity extends Activity {
    private FragmentA m1stFragment;
    private FragmentB m2ndFragment;

    // other code in your Activity...

    private class CustomPagerAdapter extends FragmentPagerAdapter {
        // other code in your custom FragmentPagerAdapter...

        public CustomPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // Do NOT try to save references to the Fragments in getItem(),
            // because getItem() is not always called. If the Fragment
            // was already created then it will be retrieved from the FragmentManger
            // and not here (i.e. getItem() won't be called again).
            switch (position) {
                case 0:
                    return new FragmentA();
                case 1:
                    return new FragmentB();
                default:
                    // This should never happen. Always account for each position above
                    return null;
            }
        }

        // Here we can finally safely save a reference to the created
        // Fragment, no matter where it came from (either getItem() or
        // FragmentManger). Simply save the returned Fragment from
        // super.instantiateItem() into an appropriate reference depending
        // on the ViewPager position.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            // save the appropriate reference depending on position
            switch (position) {
                case 0:
                    m1stFragment = (FragmentA) createdFragment;
                    break;
                case 1:
                    m2ndFragment = (FragmentB) createdFragment;
                    break;
            }
            return createdFragment;
        }
    }

    public void someMethod() {
        // do work on the referenced Fragments, but first check if they
        // even exist yet, otherwise you'll get an NPE.

        if (m1stFragment != null) {
            // m1stFragment.doWork();
        }

        if (m2ndFragment != null) {
            // m2ndFragment.doSomeWorkToo();
        }
    }
}

またはクラスメンバー変数/ tagsへの参照の代わりにFragmentsを使用したい場合は、tagsで設定されたFragmentPagerAdapterを同じ方法で取得することもできます:注:FragmentStatePagerAdapterを作成するときにtagsを設定しないため、これはFragmentsには適用されません。

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
    // get the tags set by FragmentPagerAdapter
    switch (position) {
        case 0:
            String firstTag = createdFragment.getTag();
            break;
        case 1:
            String secondTag = createdFragment.getTag();
            break;
    }
    // ... save the tags somewhere so you can reference them later
    return createdFragment;
}

このメソッドは、tagによって設定される内部FragmentPagerAdapterの模倣に依存せず、代わりに適切なAPIを使用してそれらを取得することに注意してください。このようにすると、tagの将来のバージョンでSupportLibraryが変更されても、安全です。


忘れないでくださいActivityの設計によっては、作業しようとしているFragmentsがまだ存在する場合と存在しない場合があるため、参照を使用する前にnullチェックを行うことにより、そのことを説明します。

また、代わりにFragmentStatePagerAdapterを使用している場合、Fragmentsへのハード参照を保持したくない場合があります。ハード参照は不必要にメモリ内に保持します。代わりに、Fragment参照を標準変数ではなくWeakReference変数に保存します。このような:

WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
    // reference hasn't been cleared yet; do work...
}
35
Tony Chan

私はあなたの質問に対してもう一つの比較的簡単な解決策を見つけました。

FragmentPagerAdapterソースコード からわかるように、FragmentPagerAdapterによって管理されるフラグメントは、次のコードを使用して生成されたタグの下のFragmentManagerに格納されます。

String tag="Android:switcher:" + viewId + ":" + index;

viewIdcontainer.getId()containerはあなたのViewPagerインスタンスです。 indexはフラグメントの位置です。したがって、オブジェクトIDをoutStateに保存することができます。

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("viewpagerid" , mViewPager.getId() );
}

@Override
    protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_main);
    if (savedInstanceState != null)
        viewpagerid=savedInstanceState.getInt("viewpagerid", -1 );  

    MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this);        
    mViewPager = (ViewPager) findViewById(R.id.pager);
    if (viewpagerid != -1 ){
        mViewPager.setId(viewpagerid);
    }else{
        viewpagerid=mViewPager.getId();
    }
    mViewPager.setAdapter(titleAdapter);

このフラグメントと通信したい場合は、次のようにFragmentManagerからifを取得できます。

getSupportFragmentManager().findFragmentByTag("Android:switcher:" + viewpagerid + ":0")
18
user2110066

私の答えの検索の多くは私をこのスレッドに導いていたので、私はおそらくわずかに異なるケースのための代替解決策を提供したいと思います。

私の場合 - ページを動的に作成/追加してViewPagerにスライドさせていますが、回転すると(onConfigurationChange)、もちろんOnCreateが再度呼び出されるため、新しいページが表示されます。しかし、ローテーションの前に作成されたすべてのページを参照し続けたいと思います。

問題 - 作成したフラグメントごとに一意の識別子がないため、参照する唯一の方法は、ローテーション/構成の変更後に何らかの方法で参照を配列に格納して復元することでした。

回避策 - このアクティビティではonSaveInstanceStateのBundleを利用できるため、重要な概念はアクティビティ(フラグメントを表示する)も既存のフラグメントへの参照の配列を管理することでした。

public class MainActivity extends FragmentActivity

それで、この活動の中で、私は開いているページを追跡するために個人的なメンバーを宣言します

private List<Fragment> retainedPages = new ArrayList<Fragment>();

これはonSaveInstanceStateが呼び出され、onCreateに復元されるたびに更新されます

@Override
protected void onSaveInstanceState(Bundle outState) {
    retainedPages = _adapter.exportList();
    outState.putSerializable("retainedPages", (Serializable) retainedPages);
    super.onSaveInstanceState(outState);
}

...保存されたら、取得できます。

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

    if (savedInstanceState != null) {
        retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages");
    }
    _mViewPager = (CustomViewPager) findViewById(R.id.viewPager);
    _adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager());
    if (retainedPages.size() > 0) {
        _adapter.importList(retainedPages);
    }
    _mViewPager.setAdapter(_adapter);
    _mViewPager.setCurrentItem(_adapter.getCount()-1);
}

これらは主なアクティビティに必要な変更なので、これを機能させるにはFragmentPagerAdapter内のメンバーとメソッドが必要でした。

public class ViewPagerAdapter extends FragmentPagerAdapter

同一の構成体(上記のMainActivityに示されているように)

private List<Fragment> _pages = new ArrayList<Fragment>();

この同期(onSaveInstanceStateで使用されている)は、特にメソッドによってサポートされています。

public List<Fragment> exportList() {
    return _pages;
}

public void importList(List<Fragment> savedPages) {
    _pages = savedPages;
}

そして最後に、フラグメントクラスで

public class CustomFragment extends Fragment

これらすべてを機能させるために、2つの変更がありました。

public class CustomFragment extends Fragment implements Serializable

そしてフラグメントを破壊しないようにonCreateにこれを追加する

setRetainInstance(true);

私はまだFragmentsとAndroidのライフサイクルに頭を包んでいる最中なので、この方法には冗長性と非効率性があるかもしれないことに注意してください。しかし、それは私のために動作し、私は私のようなケースで他の人に役立つかもしれないと思います。

16
Frank Yin

私の解決策は非常に失礼ですが、うまくいきます:私のフラグメントは保持されたデータから動的に作成されるので、super.onSaveInstanceState()を呼び出す前にPageAdapterからすべてのフラグメントを削除し、アクティビティ作成時に再作成します。

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putInt("viewpagerpos", mViewPager.getCurrentItem() );
    mSectionsPagerAdapter.removeAllfragments();
    super.onSaveInstanceState(outState);
}

onDestroy()でそれらを削除することはできません、そうでなければ、この例外が発生します:

Java.lang.IllegalStateException:onSaveInstanceStateの後にこのアクションを実行することはできません

これがページアダプタのコードです。

public void removeAllfragments()
{
    if ( mFragmentList != null ) {
        for ( Fragment fragment : mFragmentList ) {
            mFm.beginTransaction().remove(fragment).commit();
        }
        mFragmentList.clear();
        notifyDataSetChanged();
    }
}

フラグメントが作成された後に、現在のページを保存してonCreate()に復元するだけです。

if (savedInstanceState != null)
    mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) );  
8
Sir John

そのBasePagerAdapterは何ですか? FragmentPagerAdapterで不要になったフラグメントをそのまま保持する(前者)か、状態を保存する(後者)かのどちらかに応じて、標準のページャアダプタの1つ、FragmentStatePagerAdapterまたはViewPagerを使用します再度必要に応じて作成。

ViewPagerを使うためのサンプルコードは ここ にあります。

フレームワーク内のFragmentManagerは状態を保存し、ページャが作成したアクティブなフラグメントを復元する面倒を見るので、アクティビティインスタンス間でのビューページャ内のフラグメントの管理は少し複雑です。これが本当に意味するのは、初期化時のアダプターは、復元されたフラグメントがあれば、それと確実に再接続する必要があるということです。 FragmentPagerAdapterまたはFragmentStatePagerAdapterのコードを調べて、これがどのように行われているかを確認できます。

4
hackbod

FragmentStatePagerAdapterでフラグメントの状態が正しく復元されないという問題がある場合は、... FragmentStatePagerAdapterによって状態から復元するのではなく、新しいFragmentが作成されています。

ViewPager.setOffscreenPageLimit()を呼び出す前に、必ずViewPager.setAdapeter(fragmentStatePagerAdapter)を呼び出してください。

ViewPager.setOffscreenPageLimit()...を呼び出すと、ViewPagerは すぐに そのアダプタを調べ、そのフラグメントを取得しようとします。これは、ViewPagerがsavedInstanceStateからフラグメントを復元する機会がある前に発生する可能性があります(したがって、新しいためSavedInstanceStateから再初期化できない新しいフラグメントを作成します)。

2
dell116

私はこのシンプルでエレガントな解決策を思いつきました。アクティビティがフラグメントの作成を担当し、アダプタがそれらを処理するだけであると想定しています。

これはアダプタのコードです(mFragmentsがActivityによって管理されているフラグメントのリストであることを除けば、ここでは奇妙なことは何もありません)

class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {

    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position);
    }

    @Override
    public int getCount() {
        return mFragments.size();
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        TabFragment fragment = (TabFragment)mFragments.get(position);
        return fragment.getTitle();
    }
} 

このスレッドの全体的な問題は、「古い」フラグメントの参照を取得することなので、ActivityのonCreateでこのコードを使用します。

    if (savedInstanceState!=null) {
        if (getSupportFragmentManager().getFragments()!=null) {
            for (Fragment fragment : getSupportFragmentManager().getFragments()) {
                mFragments.add(fragment);
            }
        }
    }

もちろん、フラグメントが特定のクラスのインスタンスであることを確認するなど、必要に応じてこのコードをさらに微調整できます。

0
Merlevede

向きの変更後にフラグメントを取得するには、.getTag()を使用する必要があります。

    getSupportFragmentManager().findFragmentByTag("Android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager)

もう少し扱いやすいように、viewPagerIdとFragmentClassでフラグメントを取得するために、PageAdapter用に独自のArrayListを作成しました。

public class MyPageAdapter extends FragmentPagerAdapter implements Serializable {
private final String logTAG = MyPageAdapter.class.getName() + ".";

private ArrayList<MyPageBuilder> fragmentPages;

public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) {
    super(fm);
    fragmentPages = fragments;
}

@Override
public Fragment getItem(int position) {
    return this.fragmentPages.get(position).getFragment();
}

@Override
public CharSequence getPageTitle(int position) {
    return this.fragmentPages.get(position).getPageTitle();
}

@Override
public int getCount() {
    return this.fragmentPages.size();
}


public int getItemPosition(Object object) {
    //benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden

    Log.d(logTAG, object.getClass().getName());
    return POSITION_NONE;
}

public Fragment getFragment(int position) {
    return getItem(position);
}

public String getTag(int position, int viewPagerId) {
    //getSupportFragmentManager().findFragmentByTag("Android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem())

    return "Android:switcher:" + viewPagerId + ":" + position;
}

public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
    return new MyPageBuilder(pageTitle, icon, selectedIcon, frag);
}


public static class MyPageBuilder {

    private Fragment fragment;

    public Fragment getFragment() {
        return fragment;
    }

    public void setFragment(Fragment fragment) {
        this.fragment = fragment;
    }

    private String pageTitle;

    public String getPageTitle() {
        return pageTitle;
    }

    public void setPageTitle(String pageTitle) {
        this.pageTitle = pageTitle;
    }

    private int icon;

    public int getIconUnselected() {
        return icon;
    }

    public void setIconUnselected(int iconUnselected) {
        this.icon = iconUnselected;
    }

    private int iconSelected;

    public int getIconSelected() {
        return iconSelected;
    }

    public void setIconSelected(int iconSelected) {
        this.iconSelected = iconSelected;
    }

    public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
        this.pageTitle = pageTitle;
        this.icon = icon;
        this.iconSelected = selectedIcon;
        this.fragment = frag;
    }
}

public static class MyPageArrayList extends ArrayList<MyPageBuilder> {
    private final String logTAG = MyPageArrayList.class.getName() + ".";

    public MyPageBuilder get(Class cls) {
        // Fragment über FragmentClass holen
        for (MyPageBuilder item : this) {
            if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
                return super.get(indexOf(item));
            }
        }
        return null;
    }

    public String getTag(int viewPagerId, Class cls) {
        // Tag des Fragment unabhängig vom State z.B. nach bei Orientation change
        for (MyPageBuilder item : this) {
            if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
                return "Android:switcher:" + viewPagerId + ":" + indexOf(item);
            }
        }
        return null;
    }
}

そのため、フラグメントを使ってMyPageArrayListを作成します。

    myFragPages = new MyPageAdapter.MyPageArrayList();

    myFragPages.add(new MyPageAdapter.MyPageBuilder(
            getString(R.string.widget_config_data_frag),
            R.drawable.ic_sd_storage_24dp,
            R.drawable.ic_sd_storage_selected_24dp,
            new WidgetDataFrag()));

    myFragPages.add(new MyPageAdapter.MyPageBuilder(
            getString(R.string.widget_config_color_frag),
            R.drawable.ic_color_24dp,
            R.drawable.ic_color_selected_24dp,
            new WidgetColorFrag()));

    myFragPages.add(new MyPageAdapter.MyPageBuilder(
            getString(R.string.widget_config_textsize_frag),
            R.drawable.ic_settings_widget_24dp,
            R.drawable.ic_settings_selected_24dp,
            new WidgetTextSizeFrag()));

そしてそれらをviewPagerに追加します。

    mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages);
    myViewPager.setAdapter(mAdapter);

この後は、オリエンテーション後にそのクラスを使用して正しいフラグメントを変更できます。

        WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
            .findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
0
Scrounger