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/...
Если вы найдете что-то не так с этим подходом, прокомментируйте.