Я не могу обновить содержимое в ViewPager.
Как правильно использовать методы instantiateItem () и getItem () в классе FragmentPagerAdapter?
Я использовал только getItem () для создания экземпляров и возврата моих фрагментов:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
Это сработало хорошо. За исключением того, что я не могу изменить содержание.
Итак, я нашел это: ViewPager PagerAdapter не обновляет представление
«Мой подход заключается в использовании метода setTag () для любого экземпляра представления в методе instantiateItem ()»
Теперь я хочу реализовать instantiateItem () для этого. Но я не знаю, что я должен вернуть (тип Object) и какова связь с getItem (int position)?
Я прочитал ссылку :
публичный абстрактный фрагмент getItem (int position)
Вернуть фрагмент, связанный с указанной позицией.
открытый объект instantiateItem (контейнер ViewGroup, позиция int)
Создайте страницу для данной позиции. Адаптер отвечает за добавление представления к указанному здесь контейнеру, хотя он должен только гарантировать, что это будет сделано к тому времени, как он вернется из finishUpdate (ViewGroup). параметры
контейнер Содержащий вид, в котором будет отображаться страница. position Позиция страницы, которую нужно создать.
Возвращает
Возвращает объект, представляющий новую страницу. Это не обязательно должен быть View, но может быть какой-то другой контейнер страницы.
но я все еще не понимаю
Вот мой код. Я использую пакет поддержки v4.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
Вот также кто-то с подобной проблемой, без ответов http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html
Ответы:
При использовании FragmentPagerAdapter или FragmentStatePagerAdapter лучше всего иметь дело исключительно с,
getItem()
а не соприкасатьсяinstantiateItem()
вообще. ИнтерфейсinstantiateItem()
-destroyItem()
-isViewFromObject()
в PagerAdapter - это интерфейс более низкого уровня, который FragmentPagerAdapter использует для реализации гораздо более простогоgetItem()
интерфейса.Прежде чем углубляться в это, я должен уточнить, что
В более ранней версии этого ответа была допущена ошибка использования FragmentPagerAdapter для его примера - это не сработает, поскольку FragmentPagerAdapter никогда не уничтожает фрагмент после его первого отображения.
Я не рекомендую
setTag()
иfindViewWithTag()
обходной путь, указанный в сообщении, которое вы связали. Как вы выяснили, использование фрагментовsetTag()
иfindViewWithTag()
их использование не работает, так что это не очень хорошее совпадение.Правильное решение - переопределить
getItemPosition()
. КогдаnotifyDataSetChanged()
вызывается, ViewPager вызываетgetItemPosition()
все элементы в своем адаптере, чтобы узнать, нужно ли их переместить в другое положение или удалить.По умолчанию
getItemPosition()
возвращаетPOSITION_UNCHANGED
, что означает: «Этот объект в порядке, не разрушайте и не удаляйте его». ВозвращениеPOSITION_NONE
устраняет проблему, вместо этого говоря: «Этот объект больше не является элементом, который я отображаю, удалите его». Таким образом, он имеет эффект удаления и воссоздания каждого элемента в вашем адаптере.Это абсолютно законное решение! Это исправление заставляет notifyDataSetChanged вести себя как обычный адаптер без перезапуска представления. Если вы реализуете это исправление и производительность удовлетворительная, вы отправляетесь в гонки. Работа выполнена.
Если вам нужна лучшая производительность, вы можете использовать более изящную
getItemPosition()
реализацию. Вот пример для пейджера, создающего фрагменты из списка строк:В этой реализации будут отображаться только фрагменты с новыми заголовками. Любые фрагменты, отображающие заголовки, которые все еще находятся в списке, вместо этого будут перемещены на новую позицию в списке, а фрагменты с заголовками, которых больше нет в списке, будут уничтожены.
Что, если фрагмент не был воссоздан, но все равно нуждается в обновлении? Обновления живого фрагмента лучше всего обрабатываются самим фрагментом. В конце концов, это преимущество наличия фрагмента - это его собственный контроллер. Фрагмент может добавить слушателя или наблюдателя к другому объекту
onCreate()
, а затем удалить егоonDestroy()
, тем самым управляя обновлениями. Вам не нужно помещать весь код обновления внутрь,getItem()
как в адаптере для ListView или других типов AdapterView.И последнее: только то, что FragmentPagerAdapter не уничтожает фрагмент, не означает, что getItemPosition совершенно бесполезно в FragmentPagerAdapter. Вы все еще можете использовать этот обратный вызов для изменения порядка фрагментов в ViewPager. Однако он никогда не удалит их полностью из FragmentManager.
источник
FragmentStatePagerAdapter
, я вижу, что он удаляет мой фрагмент и создает новый экземпляр. Но новый экземпляр получает Bundle saveInstanceState с состоянием старого фрагмента. Как я могу полностью уничтожить фрагмент, чтобы Bundle был нулевым при повторном создании?Вместо того , чтобы вернуться
POSITION_NONE
изgetItemPosition()
и вызывая полный вид отдыха, сделайте следующее:Ваши фрагменты должны реализовывать
UpdateableFragment
интерфейс:и интерфейс:
Ваш класс данных:
источник
Fragment
динамически, посмотрите: stackoverflow.com/questions/19891828/…d page on refreshes the 1-st page only after swiping pages? thw 2
страницу, всегда пустую. спасибодля тех, кто все еще сталкивается с той же проблемой, с которой я сталкивался раньше, когда у меня есть
ViewPager
с 7 фрагментами. по умолчанию для этих фрагментов загружается английский контент изAPI
сервиса, но проблема здесь в том, что я хочу изменить язык из действия настроек и после завершения действия настроек я хочуViewPager
в основном действии обновить фрагменты в соответствии с выбором языка от пользователя и загрузить арабский контент, если пользователь выбирает арабский здесь, что я сделал, чтобы работать с первого раза1- Вы должны использовать FragmentStatePagerAdapter, как указано выше.
2- на mainActivity я переопределил onResume и сделал следующее
3-я переопределила
getItemPosition()
в mPagerAdapter и вернула егоPOSITION_NONE
.работает как шарм
источник
Я столкнулся с этой проблемой и, наконец, решил ее сегодня, поэтому я записываю то, что узнал, и надеюсь, что это будет полезно для тех, кто
ViewPager
плохо знаком с Android, и обновляет его, как и я. Я используюFragmentStatePagerAdapter
в API уровень 17 и в настоящее время есть только 2 фрагмента. Я думаю, что должно быть что-то не так, пожалуйста, поправьте меня, спасибо.Сериализованные данные должны быть загружены в память. Это можно сделать используя
CursorLoader
/AsyncTask
/Thread
. Будет ли он загружен автоматически, зависит от вашего кода. Если вы используетеCursorLoader
, он загружается автоматически, так как есть зарегистрированный наблюдатель данных.После вызова
viewpager.setAdapter(pageradapter)
адаптераgetCount()
постоянно вызывается для создания фрагментов. Таким образом, если данные загружаются,getCount()
можно вернуть 0, поэтому вам не нужно создавать фиктивные фрагменты, если данные не отображаются.После загрузки данных адаптер не будет автоматически строить фрагменты, так
getCount()
как он по-прежнему равен 0, поэтому мы можем установить фактически загруженный номер данных, который будет возвращенgetCount()
, а затем вызвать адаптерnotifyDataSetChanged()
.ViewPager
начать создавать фрагменты (только первые 2 фрагмента) по данным в памяти. Это сделано, прежде чемnotifyDataSetChanged()
возвращается. Тогда у васViewPager
есть нужные вам фрагменты.Если данные в базе данных и памяти оба обновлены (запись через), или только данные в памяти обновлены (обратная запись), или обновлены только данные в базе данных. В двух последних случаях, если данные автоматически не загружаются из базы данных в память (как упоминалось выше).
ViewPager
И адаптер пейджера просто иметь дело с данными в памяти.Поэтому, когда данные в памяти обновляются, нам просто нужно вызвать адаптер
notifyDataSetChanged()
. Поскольку фрагмент уже создан, адаптерonItemPosition()
будет вызван доnotifyDataSetChanged()
возврата. Ничего не нужно делать вgetItemPosition()
. Затем данные обновляются.источник
notifyDataSetChanged()
затем просто обновитесь автоматически, потому что фрагмент (с диаграммой), который я использую, обновится сам. если это не так, как статический фрагмент, мне придется позвонитьonItemPositon()
иPOSITION_NONE
Попробуйте
destroyDrawingCache()
на ViewPager послеnotifyDataSetChanged()
в вашем коде.источник
Fragments
в своем видении пейджер. Так что спасибо тебе!После нескольких часов разочарования при попытке всех вышеуказанных решений , чтобы преодолеть эту проблему , а также пытается множество решений на других подобные вопросы , как это , это и это , который все FAILED со мной , чтобы решить эту проблему и сделать ,
ViewPager
чтобы разрушить староеFragment
и заполнитьpager
с новыйFragment
с. Я решил проблему следующим образом:1) Сделайте так, чтобы
ViewPager
класс расширялсяFragmentPagerAdapter
следующим образом:2) Создайте элемент для
ViewPager
храненияtitle
иfragment
следующих действий:3) Создайте конструктор объекта
ViewPager
take myFragmentManager
для сохранения его в myclass
следующим образом:4) Создайте метод для переустановки
adapter
данных с новыми данными, удалив все предыдущие непосредственноfragment
из самогоfragmentManager
себя, чтобыadapter
снова установить новыйfragment
из нового списка следующим образом:5) Из контейнера
Activity
илиFragment
не переинициализируйте адаптер с новыми данными. Установите новые данные с помощью методаsetPagerItems
с новыми данными следующим образом:Я надеюсь, что это помогает.
источник
По какой-то причине ни один из ответов не сработал для меня, поэтому мне пришлось переопределить метод restoreState, не вызывая super в моем fragStatePagerAdapter. Код:
источник
Я немного изменил решение, предоставленное Биллом Филлипсом, чтобы удовлетворить мои потребности
так что
getItemPosition()
возвращаетсяPOSITION_NONE
только для тех фрагментов, которые в данный момент вFragmentManager
когдаgetItemPosition
вызывается. (Обратите внимание, что этоFragmentStatePager
иViewPager
связанное с ним содержится во фрагменте, а не в действии)источник
У меня была похожая проблема, но я не хочу доверять существующим решениям (жестко закодированные имена тегов и т. Д.), И я не мог заставить решение M-WaJeEh работать на меня. Вот мое решение:
Я храню ссылки на фрагменты, созданные в getItem в массиве. Это работает нормально, пока действие не уничтожено из-за configurationChange или нехватки памяти или чего-либо еще (-> при возвращении к действию фрагменты возвращаются в свое последнее состояние без повторного вызова getItem и, следовательно, без обновления массива ).
Чтобы избежать этой проблемы, я реализовал instantiateItem (ViewGroup, int) и обновил там мой массив, например так:
Итак, с одной стороны, я счастлив, что нашел решение, которое работает для меня, и хотел бы поделиться им с вами, но я также хотел спросить, пробовал ли кто-то что-то подобное и есть ли причина, почему я не должен сделать это так? Пока это работает очень хорошо для меня ...
источник
myFragments
in,public void destroyItem(ViewGroup container, int position, Object object)
а также, чтобы вы не захватили устаревшую ссылку на fragement.Я использую библиотеку EventBus для обновления
Fragment
контента вViewPager
. Логика проста, как документ EventBus, как это сделать . Не нужно контролироватьFragmentPagerAdapter
экземпляр. Код здесь:1: Определить события
Определите, какое сообщение необходимо обновить.
2. Подготовить подписчиков
Напишите ниже код во фрагменте, который необходимо обновить.
3.Пост события
Напишите ниже код в другом
Activity
или другом,Fragment
который должен обновить параметристочник
Если вы хотите использовать FragmentStatePagerAdapter, ознакомьтесь с https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% 20Stars & groupby = & sort = & id = 37990 . Существуют проблемы с FragmentStatePagerAdapter, которые могут вызывать или не беспокоить ваш вариант использования.
Кроме того, ссылка имеет несколько решений .. мало кто может удовлетворить ваши требования.
источник
Я жил той же проблемой, и я искал слишком много раз. Любой ответ, данный в stackoverflow или через Google, не был решением для моей проблемы. Моя проблема была легкой. У меня есть список, я показываю этот список с ViewPager. Когда я добавляю новый элемент в заголовок списка и обновляю ничего не изменилось. Мое окончательное решение было очень простым для любого. Когда новый элемент добавлен в список и хотите обновить список. Сначала установите для адаптера viewpager значение null, затем заново создайте адаптер и установите для него значение i для viewpager.
Убедитесь, что ваш адаптер должен расширять FragmentStatePagerAdapter
источник
Вот моя реализация, которая включает в себя информацию от @Bill Phillips One большую часть времени получает фрагментированное кэширование, за исключением случаев, когда данные изменились. Просто, и, кажется, работает нормально.
MyFragmentStatePagerAdapter.java
MyActivity.java
источник
Я пробовал так много разных подходов, и ни один из них не помог мне. Ниже я расскажу, как я могу решить эту проблему с помощью набора решений, предоставленных всеми вами. Спасибо всем.
Я только хочу обновить страницу 0 после onResume ().
В моем FragmentsMain есть общедоступное целое число «страница», которое может сказать мне, является ли это страница, которую я хочу обновить.
источник
Я знаю, что опаздываю на вечеринку. Я исправил проблему, позвонив
TabLayout#setupWithViewPager(myViewPager);
сразу послеFragmentPagerAdapter#notifyDataSetChanged();
источник
Это решение не будет работать для всех, но в моем случае каждый фрагмент в моем ViewPager - это отдельный класс, и одновременно существует только один из них.
С этим ограничением это решение является безопасным и должно быть безопасным для использования в производстве.
Если у вас есть несколько версий одного и того же фрагмента, вы можете использовать эту же стратегию для вызова методов этих фрагментов, чтобы определить, является ли это фрагмент, который вы хотите обновить.
источник
Это может кому-то помочь - в моем случае при вставке новой страницы пейджер просмотра дважды запрашивал позицию существующего фрагмента, но не спрашивал позицию нового элемента, вызывая неправильное поведение и не отображая данные.
Скопируйте исходный код для FragmentStatePagerAdapter (кажется, не обновлялся веками).
Переопределить notifyDataSetChanged ()
Добавьте проверку работоспособности для destroyItem (), чтобы предотвратить сбои:
источник
Я просмотрел все ответы выше и ряд других постов, но так и не смог найти что-то подходящее для меня (с разными типами фрагментов и динамическим добавлением и удалением вкладок). FWIW следующий подход - это то, что сработало для меня (в случае, если у кого-то еще есть такие же проблемы).
источник
Используйте FragmentStatePagerAdapter вместо FragmentPagerAdapter, если вы хотите воссоздать или перезагрузить фрагмент на основе индекса. Например, если вы хотите перезагрузить фрагмент, отличный от FirstFragment, вы можете проверить экземпляр и вернуть позицию следующим образом
источник
Вам нужно изменить элемент mFragments для экземпляра getItemPosition.
Основан на AndroidX FragmentStatePagerAdapter.java, поскольку
mFragments
положение элементов не изменяется при вызове notifyDataSetChanged ().Источник: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java
Пример: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt
Вы можете запустить этот проект, чтобы подтвердить, как работать. https://github.com/cuichanghao/infivt
источник