Подтвердить что ты не робот

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

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

4b9b3361

Ответ 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). Возможно, я ошибаюсь, поэтому, пожалуйста, поправьте меня....

(Извините за мой английский)