FragmentPagerAdapter - Как обрабатывать изменения ориентации?
Я использую FragmentPagerAdapter
, содержащий несколько фрагментов, которые необходимо уведомить об изменениях в database
. Я делаю это путем перебора фрагментов, которые реализуют интерфейс обратного вызова, и вызова метода refreshData()
.
Это работает просто отлично, пока устройство не изменит ориентацию. После изменения ориентации пользовательский интерфейс фрагмента не обновляется, хотя вызов метода, похоже, работает.
Из того, что я прочитал до сих пор, это происходит потому, что FragmentPagerAdapter
обрабатывает жизненный цикл фрагментов, а фрагменты, которые получают обратный вызов, не являются теми, которые фактически отображаются.
private class DataPagerAdapter extends FragmentPagerAdapter {
private DataFragment[] fragments = new DataFragment[] {
new FooDataFragment(), BarDataFragment()};
public DataPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments[position];
}
@Override
public int getCount() {
return fragments.length;
}
public DataFragment[] getFragments() {
return fragments;
}
}
protected void refreshData() {
for (DataFragment dataFragment : mPagerAdapter.getFragments()) {
dataFragment.refreshData();
}
Я временно исправил эту проблему, используя приемник вещания внутри каждого фрагмента, но это решение кажется расточительным и может привести к утечкам памяти. Как исправить это правильно? Я использую другой макет и логику в ландшафтном режиме, поэтому я хочу использовать вновь созданные фрагменты после изменения ориентации.
Ответы
Ответ 1
Да, как вы сказали, FragmentManager обрабатывает фрагменты после изменения ориентации, поэтому getItem
в адаптере не вызывается. Но вы можете переопределить метод instantiateItem()
, который вызывается даже после изменения ориентации и отбрасывает объект в фрагмент и сохраняет его в вашем массиве.
@Override
public Object instantiateItem(ViewGroup container, int position) {
DataFragment fragment = (DataFragment) super.instantiateItem(container, position);
fragments[position] = fragment;
return fragment;
}
Ответ 2
Не могли бы вы просто установить флаг android: configChanges для вашей активности в AndroidManifest.xml, чтобы предотвратить воссоздание активности?
<activity
android:name="com.example.test.activity.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"/>
также там вы можете найти больше возможностей:https://android.jlelse.eu/handling-orientation-changes-in-android-7072958c442a
Ответ 3
Я заново создал адаптер пейджера в методе onResume:
override fun onResume() {
super.onResume()
val viewPager = findViewById<ViewPager>(R.id.my_view_pager)
viewPager.adapter = MyPagerAdapter(supportFragmentManager)
}
Ответ 4
У меня была аналогичная проблема с моим рабочим решением:
В действии, где есть вызов адаптера adapter.notifyDataSetChanged();
переопределить метод getItemPostion() в вашем адаптере
@Override
public int getItemPosition(Object object) {
MyFragment frag = (MyFragment)object;
frag.refresh();
return POSITION_UNCHANGED;
}
my FragmentStatePagerAdapater
(мой адаптер) содержит только один тип фрагмента, но я думаю, что вы могли бы использовать instanceof
(для большего количества типов фрагментов), а затем использовать листинг, или каждый фрагмент будет реализовывать интерфейс с методом refresh()
Затем добавьте метод refresh()
в свой фрагмент и используйте эту реализацию:
public void refresh() {
LayoutInflater inflater = LayoutInflater.from(getActivity());
ViewGroup viewGroup = (ViewGroup) getView();
viewGroup.removeAllViewsInLayout();
View view = onCreateView(inflater, viewGroup, null);
viewGroup.addView(view);
}
Это сработало для меня.
Мое мнение:
Проблема возникла, когда устройство изменило ориентацию, адаптер был разрушен, но фрагменты все еще находятся в памяти, и система пытается повторно использовать их после изменения ориентации, но виды, которые содержатся в фрагментах, также уничтожаются, а фрагменты должны быть "воссоздать" (вызов метода onCreateView
). Возможно, я ошибаюсь, поэтому, пожалуйста, поправьте меня....
(Извините за мой английский)