FragmentPagerAdapter с ViewPager и двумя фрагментами. Перейти к первому из второго и обновить первый текст

Я не знаком с FragmentPagerAdapterтак что это будет один из тех вопросов, которые мы (вы) читаем в описании критически.

Структура: у меня есть FragmentPagerAdapter (код ниже), который будет содержать два фрагмента за раз. Первый отображает выдержки из книг, а второй - список названий книг.

Цель: я хочу добиться того, что описано в заголовке: пользователь может перейти ко второму фрагменту в пейджере, щелкнуть заголовок, а затем я хочу переместить пользователя обратно к первому фрагменту и сказать первому фрагменту обновить текст. Первый фрагмент имеет triggerRefresh метод для этого.

Код: я считаю, что моя проблема происходит из-за способа FragmentPagerAdapter повторно использует / создает фрагменты (чего я не понимаю). Это мой класс:

static class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        switch(position) {
        case 0:
            return new ExcerptsFragment();
        case 1:
            return new BookListFragment();
        default:
            throw new IllegalArgumentException("not this many fragments: " + position);
        }
    }
}

Вот как я создал соответствующих участников:

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
MyFragmentPagerAdapter mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mFragmentPagerAdapter);

И это то, что я пробовал в другом месте в моей Деятельности, когда я получаю обратный вызов от названия книги Фрагмент с выбранным названием:

mViewPager.setCurrentItem(0); // back to excerpts screen page. It's OK.
// Here's the problem! How to identify the fragment 0 
// to ExcerptsFragment and call its triggerRefresh()?!?

Серия проблем:

Вызов адаптера getView() не будет работать, потому что он вернет новый экземпляр ExcerptsFragment, который в данный момент не прикреплен (как и ожидалось, выдает исключение).

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

Какие-либо предложения? Я не удивлюсь, если я не пойму все это немного...

3 ответа

Решение

Отказ от ответственности: Хотя раньше это прекрасно работало для меня, вы должны знать о классических ловушках зависимости от внутреннего, личного поведения. В то время как я писал тесты, которые в конечном итоге предупредили бы меня, если внутренняя реализация изменилась, я с тех пор перешел на более зеленые пастбища. И ты должен тоже. Таким образом, ценность этого вопроса и его ответ являются только историческими, на мой взгляд.


Извините за этот вопрос, я думаю, что это был час.

Чтобы решить эту проблему, я реализовал это решение как есть. Кажется, работает просто отлично. Итак, я полагаю, что это был просто вопрос поиска (в настоящее время присоединенного) экземпляра фрагмента путем выяснения, как называется его Id. Ссылка выше объясняет, как это сделано.

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

Во всяком случае, вот последний кусок кода, который мне нужен (прокомментированная часть выше):

int n = 0;
mViewPager.setCurrentItem(n); // in the question I had stopped here.

ExcerptsFragment f = (ExcerptsFragment) ContainerActivity.this
        .getSupportFragmentManager().findFragmentByTag(getFragmentTag(n));
f.triggerRefresh();

// ... below the helper method: used the solution from the link.

private String getFragmentTag(int pos){
    return "android:switcher:"+R.id.pager+":"+pos;
}

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

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

Я сам некоторое время искал решение этой проблемы. Ваш подход в принципе работает, но он сломает ваш код, если когда-либо изменится код создания тега фрагмента в реализации базового класса Android. Это довольно неприятная зависимость!

Более элегантный подход заключается в том, чтобы перевернуть проблему и сохранить экземпляр вашей базовой активности в своем фрагменте. Реализуйте установщик для тега в своей деятельности и вызывайте его внутри фрагмента при создании - тег там просто доступен с помощью getTag().

Пример реализации можно найти здесь.

Я решил эту проблему, используя WeakReferences для фрагментов при создании. См.: /questions/18270194/kak-poluchit-suschestvuyuschie-fragmentyi-pri-ispolzovanii-fragmentpageradapter/18270228#18270228

Если вы нашли что-то не так с этим подходом, пожалуйста, прокомментируйте.

Другие вопросы по тегам