FragmentPagerAdapter - Как обрабатывать изменения ориентации?
Я использую FragmentPagerAdapter, содержащий несколько фрагментов, которые необходимо уведомлять об изменениях в базе данных. Я делаю это путем перебора фрагментов, которые реализуют интерфейс обратного вызова, и вызова метода 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();
}
Я временно исправил эту проблему, используя приемник вещания внутри каждого фрагмента, но это решение кажется расточительным и может привести к утечкам памяти. Как исправить это правильно? Я использую другой макет и логику в ландшафтном режиме, поэтому я хочу использовать вновь созданные фрагменты после изменения ориентации.
2 ответа
Да, как вы сказали, FragmentManager обрабатывает фрагменты после изменения ориентации, так getItem
в адаптере не называется. Но вы можете переопределить метод instantiateItem()
который вызывается даже после изменения ориентации и приводит объект к фрагменту и сохраняет его в массиве.
@Override
public Object instantiateItem(ViewGroup container, int position) {
DataFragment fragment = (DataFragment) super.instantiateItem(container, position);
fragments[position] = fragment;
return fragment;
}
Не могли бы вы просто установить флаг 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
Я воссоздал адаптер пейджера в методе onResume:
override fun onResume() {
super.onResume()
val viewPager = findViewById<ViewPager>(R.id.my_view_pager)
viewPager.adapter = MyPagerAdapter(supportFragmentManager)
}
У меня была похожая проблема моего рабочего решения: в деятельности, где вызов адаптера adapter.notifyDataSetChanged();
переопределить метод getItemPostion() в вашем адаптере
@Override
public int getItemPosition(Object object) {
MyFragment frag = (MyFragment)object;
frag.refresh();
return POSITION_UNCHANGED;
}
мой 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
метод). Может быть, я ошибаюсь, поэтому, пожалуйста, поправьте меня...
(Извините за мой английский)