ViewPager и fragmentы – какой способ сохранить состояние fragmentа?

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

редактировать

См. Немой вариант ниже 😉

Объем

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

проблема

Когда активность воссоздается (например, при изменении ориентации), так же, как и fragmentы ViewPager . Код (вы найдете ниже) говорит, что каждый раз, когда создается действие, я пытаюсь создать новый ViewPager fragmentов ViewPager же, как и fragmentы (может быть, это проблема), но FragmentManager уже имеет все эти fragmentы где-то (где?) и запускает механизм restа для них. Таким образом, механизм restа вызывает «старый» fragment onAttach, onCreateView и т. Д. С моим вызовом интерфейса обратного вызова для инициирования данных с помощью реализованного метода Activity. Но этот метод указывает на вновь созданный fragment, созданный с помощью метода 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 screens = new LinkedHashMap(); 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 mScreens; public BasePagerAdapter(Map 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 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(); 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... */ } 

Решение

Глубокое решение состоит в том, чтобы сохранить fragmentы внутри onSaveInstanceState (активности хозяина) с помощью 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(); ... } 

Когда FragmentPagerAdapter добавляет fragment в FragmentManager, он использует специальный тег, основанный на конкретной позиции, в которой будет размещен fragment. FragmentPagerAdapter.getItem(int position) вызывается только тогда, когда fragment для этой позиции не существует. После поворота Android заметит, что он уже создал / сохранил fragment для этой конкретной позиции и поэтому просто пытается подключиться к нему с помощью FragmentManager.findFragmentByTag() вместо создания нового. Все это становится бесплатным при использовании FragmentPagerAdapter и поэтому обычно имеет код инициализации fragmentа внутри метода getItem(int) .

Даже если мы не использовали FragmentPagerAdapter , не рекомендуется создавать новый fragment каждый раз в Activity.onCreate(Bundle) . Как вы заметили, когда fragment добавлен в FragmentManager, он будет воссоздан для вас после поворота, и нет необходимости добавлять его снова. Это является общей причиной ошибок при работе с fragmentами.

Обычный подход при работе с fragmentами заключается в следующем:

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

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

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

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

Я хочу предложить решение, которое расширится на замечательный ответ antonyt и упомянет об переопределении 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 (ie 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 вместо переменных-членов classа / ссылок на 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 m1stFragment = new WeakReference(createdFragment); // ...and access them like so Fragment firstFragment = m1stFragment.get(); if (firstFragment != null) { // reference hasn't been cleared yet; do work... } 

Я нашел другое относительно простое решение для вашего вопроса.

Как вы можете видеть из исходного кода FragmentPagerAdapter , fragmentы, управляемые FragmentPagerAdapter хранятся в FragmentManager под тегом, сгенерированным с использованием:

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

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

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

 getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0") 

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

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

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

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

 public class MainActivity extends FragmentActivity 

Поэтому в рамках этой операции я объявляю частного участника для отслеживания открытых страниц

 private List retainedPages = new ArrayList(); 

Это обновляется каждый раз, когда вызывается и восстанавливаетсяSaveInstanceState в 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) 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 _pages = new ArrayList(); 

и эта синхронизация (как используется выше в onSaveInstanceState) поддерживается, в частности, методами

 public List exportList() { return _pages; } public void importList(List savedPages) { _pages = savedPages; } 

И наконец, в classе fragmentов

 public class CustomFragment extends Fragment 

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

 public class CustomFragment extends Fragment implements Serializable 

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

 setRetainInstance(true); 

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

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

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

Вы не можете удалить их в onDestroy() , иначе вы получите это исключение:

java.lang.IllegalStateException: не onSaveInstanceState выполнить это действие после onSaveInstanceState

Здесь код в адаптере страницы:

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

Я сохраняю только текущую страницу и восстанавливаю ее в onCreate() после создания fragmentов.

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

Что такое BasePagerAdapter ? Вы должны использовать один из стандартных адаптеров пейджера – либо FragmentPagerAdapter либо FragmentStatePagerAdapter , в зависимости от того, хотите ли вы, чтобы fragmentы, которые больше не нужны ViewPager либо поддерживаются (первые), либо сохраняются в их состоянии (последним) и повторно – если необходимо, снова создайте.

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

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

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

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

При вызове ViewPager.setOffscreenPageLimit() … ViewPager немедленно посмотрит на свой адаптер и попытается получить его fragmentы. Это может произойти до того, как у ViewPager появилась возможность восстановить fragmentы из savedInstanceState (таким образом создавая новые fragmentы, которые нельзя повторно инициализировать из SavedInstanceState, потому что они новы).

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

Это код адаптера (здесь нет ничего странного, кроме факта, что mFragments – это список fragmentов, поддерживаемых 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(); } } 

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

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

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

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

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

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

 public class MyPageAdapter extends FragmentPagerAdapter implements Serializable { private final String logTAG = MyPageAdapter.class.getName() + "."; private ArrayList fragmentPages; public MyPageAdapter(FragmentManager fm, ArrayList 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 { 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 zB 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 с fragmentами:

  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); 

после этого вы можете получить после изменения ориентации правильный fragment, используя его class:

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

Добавить:

  @SuppressLint("ValidFragment") 

перед вашим classом.

он не работает, делает что-то вроде этого:

 @SuppressLint({ "ValidFragment", "HandlerLeak" }) 
  • Лучший способ использования StructureMap для реализации шаблона страtagsи
  • Является ли ServiceLocator анти-шаблоном?
  • Почему и как избежать утечек памяти обработчика событий?
  • Лучший шаблон дизайна для функции «отменить»
  • Синглтон, поясняющий Джон Скит
  • Шаблон дизайна для Undo Engine
  • Что такое MVP и MVC и в чем разница?
  • В чем разница между шаблонами зависимостей зависимостей и шаблонов Locator?
  • Как автоматически регистрировать class при создании
  • Шаблоны проектирования: абстрактный завод по сравнению с заводским методом
  • Что такое инъекция зависимости?
  • Давайте будем гением компьютера.