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 ака помощник
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 (хоста 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();
...
}
10 ответов
Когда 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 (короткий) и ViewPager (длинный).
Я хочу предложить решение, которое расширяет 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 (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...
}
Я нашел другое относительно простое решение для вашего вопроса.
Как видно из исходного кода 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);
Если вы хотите общаться с этим фрагментом, вы можете получить, если от FragmentManager
, такие как:
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
Я хочу предложить альтернативное решение для, возможно, немного другого случая, так как многие из моих поисков ответов продолжали приводить меня к этой теме.
Мой случай - я создаю / добавляю страницы динамически и помещаю их в 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, поэтому предостережение здесь может заключаться в избыточности / неэффективности в этом методе. Но это работает для меня, и я надеюсь, что может быть полезным для других в случаях, подобных моему.
Мое решение очень грубое, но работает: так как мои фрагменты динамически создаются из сохраненных данных, я просто удаляю все фрагменты из 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 ) );
Что это такое BasePagerAdapter
? Вы должны использовать один из стандартных адаптеров пейджера - либо FragmentPagerAdapter
или же FragmentStatePagerAdapter
в зависимости от того, хотите ли вы фрагменты, которые больше не нужны ViewPager
либо сохранить (первый), либо сохранить его состояние (последний) и заново создать, если необходимо, снова.
Пример кода для использования ViewPager
можно найти здесь
Это правда, что управление фрагментами в пейджере представлений между экземплярами операций немного сложнее, потому что FragmentManager
в рамках заботится о сохранении состояния и восстановлении любых активных фрагментов, которые сделал пейджер. Все это действительно означает, что адаптер при инициализации должен убедиться, что он повторно соединяется с любыми восстановленными фрагментами. Вы можете посмотреть на код для FragmentPagerAdapter
или же FragmentStatePagerAdapter
чтобы увидеть, как это делается.
Если у кого-то возникают проблемы с его FragmentStatePagerAdapter, неправильно восстанавливающего состояние его фрагментов... то есть... новые фрагменты создаются FragmentStatePagerAdapter вместо того, чтобы восстанавливать их из состояния...
Убедитесь, что вы звоните ViewPager.setOffscreenPageLimit()
ДО того, как вы позвоните ViewPager.setAdapeter(fragmentStatePagerAdapter)
По вызову ViewPager.setOffscreenPageLimit()
... ViewPager немедленно посмотрит на свой адаптер и попытается получить его фрагменты. Это может произойти до того, как ViewPager сможет восстановить фрагменты из saveInstanceState (создавая новые фрагменты, которые не могут быть повторно инициализированы из SavedInstanceState, потому что они новые).
Немного другое мнение, вместо того, чтобы хранить фрагменты самостоятельно, просто оставьте это FragmentManager, а когда вам нужно что-то сделать с фрагментами, поищите их в FragmentManager:
//make sure you have the right FragmentManager
//getSupportFragmentManager or getChildFragmentManager depending on what you are using to manage this stack of fragments
List<Fragment> fragments = fragmentManager.getFragments();
if(fragments != null) {
int count = fragments.size();
for (int x = 0; x < count; x++) {
Fragment fragment = fragments.get(x);
//check if this is the fragment we want,
//it may be some other inspection, tag etc.
if (fragment instanceof MyFragment) {
//do whatever we need to do with it
}
}
}
Если у вас много фрагментов и стоимость проверки instanceof может быть не такой, какой вы хотите, но хорошо иметь в виду, что FragmentManager уже ведет учет фрагментов.
Я придумал это простое и элегантное решение. Предполагается, что действие отвечает за создание фрагментов, а адаптер просто обслуживает их.
Это код адаптера (здесь нет ничего странного, за исключением того факта, что mFragments
это список фрагментов, поддерживаемый Деятельностью)
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);
}
}
}
Конечно, вы можете дополнительно настроить этот код при необходимости, например, убедившись, что фрагменты являются экземплярами определенного класса.
Чтобы получить фрагменты после изменения ориентации, вы должны использовать.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));
Добавлять:
@SuppressLint("ValidFragment")
перед вашим классом.
это не работает, сделайте что-то вроде этого:
@SuppressLint({ "ValidFragment", "HandlerLeak" })