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