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 OK.
// Here the problem! How to identify the fragment 0 
// to ExcerptsFragment and call its triggerRefresh()?!?

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

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

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

Любые предложения? Я не удивлюсь, если я не пойму все это одно...

Ответ 1

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


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

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

Я решил эту проблему, используя WeakReferences для фрагментов при создании. См.: fooobar.com/info/14320/...

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