it-swarm.com.ru

ViewPager и фрагменты - как правильно сохранить состояние фрагмента?

Фрагменты, кажется, очень хороши для разделения логики пользовательского интерфейса на некоторые модули. Но вместе с ViewPager его жизненный цикл все еще остается для меня туманным. Поэтому мысли Гуру крайне необходимы!

Правка

Смотрите тупое решение ниже ;-)

Объем

Основная деятельность имеет ViewPager с фрагментами. Эти фрагменты могут реализовывать несколько иную логику для других (подосновных) действий, поэтому данные фрагментов заполняются через интерфейс обратного вызова внутри действия. И все отлично работает при первом запуске, но! ...

Проблема

Когда действие воссоздается (например, при изменении ориентации), делайте также фрагменты ViewPager. Код (вы найдете ниже) говорит, что каждый раз, когда создается действие, я пытаюсь создать новый адаптер фрагментов ViewPager так же, как фрагменты (возможно, это проблема), но FragmentManager уже где-то хранит все эти фрагменты (где?) и запускает механизм отдыха для тех. Таким образом, механизм восстановления вызывает "старый" фрагмент onAttach, onCreateView и т.д. С моим вызовом интерфейса обратного вызова для инициирования данных через реализованный метод Activity. Но этот метод указывает на вновь созданный фрагмент, который создается с помощью метода onCreate в Activity.

Вопрос

Возможно, я использую неправильные шаблоны, но даже в Android 3 Pro книге об этом мало говорится. Итак, пожалуйста, дай мне один-два удара и укажи, как сделать это правильно. Большое спасибо!

Код

Основная деятельность

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 aka helper

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... */
}

Решение

Тупое решение - сохранить фрагменты внутри onSaveInstanceState (Host Activity) с помощью putFragment и получить их внутри onCreate через getFragment. Но у меня все еще есть странное чувство, что вещи не должны работать так ... Смотрите код ниже:

    @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();
    ...
}
476
Aleksey Malevaniy

Когда 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 мы отказываемся от управления фрагментами адаптера и не должны выполнять вышеуказанные действия. По умолчанию он предварительно загружает только один фрагмент впереди и позади текущей позиции (хотя он не уничтожает их, если вы не используете FragmentStatePagerAdapter). Это контролируется с помощью ViewPager.setOffscreenPageLimit (int) . Из-за этого прямой вызов методов для фрагментов вне адаптера не гарантируется как допустимый, поскольку они могут даже не существовать.

Короче говоря, ваше решение использовать putFragment, чтобы иметь возможность впоследствии получить ссылку, не настолько безумно и не так уж отличается от обычного способа использовать фрагменты в любом случае (см. Выше). В противном случае получить ссылку сложно, поскольку этот фрагмент добавляется адаптером, а не вами лично. Просто убедитесь, что offscreenPageLimit достаточно высока, чтобы всегда загружать нужные фрагменты, поскольку вы полагаетесь на его присутствие. Это обходит возможности отложенной загрузки ViewPager, но, похоже, это то, что вы хотите для своего приложения.

Другой подход заключается в переопределении FragmentPageAdapter.instantiateItem(View, int) и сохранении ссылки на фрагмент, возвращенный из супер-вызова, перед его возвратом (он имеет логику для поиска фрагмента, если он уже присутствует).

Для более полной картины взгляните на некоторые из источников FragmentPagerAdapter (short) и ViewPager (long).

441
antonyt

Я хочу предложить решение, которое расширяет antonyt 's замечательный ответ и упоминает переопределение FragmentPageAdapter.instantiateItem(View, int) для сохранения ссылок на созданную Fragments, чтобы вы могли может сделать работу над ними позже. Это также должно работать с 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;

viewId - это container.getId(), container - это ваш ViewPager экземпляр. index - это позиция фрагмента. Следовательно, вы можете сохранить идентификатор объекта в 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);

Если вы хотите связаться с этим фрагментом, вы можете получить if из FragmentManager, например:

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

Я хочу предложить альтернативное решение для, возможно, немного другого случая, поскольку многие из моих поисков ответов продолжали вести меня к этой теме.

в моем случае - я создаю/добавляю страницы динамически и помещаю их в ViewPager, но при повороте (onConfigurationChange) я получаю новую страницу, потому что, конечно, OnCreate вызывается снова. Но я хочу сохранить ссылку на все страницы, которые были созданы до ротации.

Проблема - У меня нет уникальных идентификаторов для каждого фрагмента, который я создаю, поэтому единственный способ ссылки был каким-то образом хранить ссылки в массиве, который будет восстановлен после изменения ротации/конфигурации.

Обходной путь - Ключевая концепция заключалась в том, чтобы Activity (которая отображает фрагменты) также управляла массивом ссылок на существующие фрагменты, поскольку это действие может использовать Bundles в onSaveInstanceState.

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

для того, чтобы все это заработало, было сделано два изменения:

public class CustomFragment extends Fragment implements Serializable

а затем добавить это в onCreate, чтобы фрагменты не были уничтожены

setRetainInstance(true);

Я все еще нахожусь в процессе обдумывания фрагментов и жизненного цикла Android, поэтому предостережение здесь может заключаться в избыточности/неэффективности этого метода. Но это работает для меня, и я надеюсь, что может быть полезным для других в случаях, подобных моему.

16
Frank Yin

Мое решение очень грубое, но работает: так как мои фрагменты динамически создаются из сохраненных данных, я просто удаляю все фрагменты из PageAdapter перед вызовом super.onSaveInstanceState() и затем воссоздаю их при создании активности:

@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 или FragmentStatePagerAdapter, в зависимости от того, хотите ли вы, чтобы фрагменты, которые больше не нужны ViewPager, либо сохранялись (первый), либо сохранялись их состояния (последний) и повторно -создан при необходимости снова.

Пример кода для использования ViewPager можно найти здесь

Это правда, что управление фрагментами в пейджере представления между экземплярами операций немного сложнее, потому что FragmentManager в структуре заботится о сохранении состояния и восстановлении любых активных фрагментов, которые создал пейджер. Все это действительно означает, что адаптер при инициализации должен убедиться, что он повторно соединяется с любыми восстановленными фрагментами. Вы можете посмотреть на код для FragmentPagerAdapter или FragmentStatePagerAdapter, чтобы увидеть, как это делается.

4
hackbod

Если у кого-то возникают проблемы с его FragmentStatePagerAdapter, неправильно восстанавливающего состояние его фрагментов ... то есть ... новые фрагменты создаются FragmentStatePagerAdapter вместо того, чтобы восстанавливать их из состояния ...

Убедитесь, что вы вызываете ViewPager.setOffscreenPageLimit() ПРЕЖДЕ ЧЕМ вы вызываете ViewPager.setAdapeter(fragmentStatePagerAdapter)

После вызова ViewPager.setOffscreenPageLimit()... ViewPager немедленно найдет свой адаптер и попытается получить его фрагменты. Это может произойти до того, как ViewPager сможет восстановить фрагменты из saveInstanceState (создавая новые фрагменты, которые не могут быть повторно инициализированы из 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();
    }
} 

Вся проблема этого потока заключается в получении ссылки на "старые" фрагменты, поэтому я использую этот код в onCreate Activity.

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

Конечно, вы можете дополнительно настроить этот код при необходимости, например, убедившись, что фрагменты являются экземплярами определенного класса.

0
Merlevede

Чтобы получить фрагменты после изменения ориентации, вы должны использовать .getTag ().

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

Для большей обработки я написал свой собственный ArrayList для моего PageAdapter, чтобы получить фрагмент по viewPagerId и FragmentClass в любой позиции:

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