ViewPager PagerAdapter不更新视图

我正在使用兼容性库中的ViewPager。 我成功地把它展示了几个我可以翻阅的视图。

不过,我很难弄清楚如何用一组新的视图来更新ViewPager。

我已经尝试了各种各样的东西,比如调用mAdapter.notifyDataSetChanged()mViewPager.invalidate()每次我想使用一个新的数据列表,甚至创build一个全新的适配器。

没有什么帮助,文本观点与原始数据保持不变。

更新:我做了一个小testing项目,我几乎可以更新视图。 我将粘贴下面的课程。

但是没有出现更新的是第二个视图,“B”仍然存在,按下更新button后应该显示“Y”。

 public class ViewPagerBugActivity extends Activity { private ViewPager myViewPager; private List<String> data; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); data = new ArrayList<String>(); data.add("A"); data.add("B"); data.add("C"); myViewPager = (ViewPager) findViewById(R.id.my_view_pager); myViewPager.setAdapter(new MyViewPagerAdapter(this, data)); Button updateButton = (Button) findViewById(R.id.update_button); updateButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { updateViewPager(); } }); } private void updateViewPager() { data.clear(); data.add("X"); data.add("Y"); data.add("Z"); myViewPager.getAdapter().notifyDataSetChanged(); } private class MyViewPagerAdapter extends PagerAdapter { private List<String> data; private Context ctx; public MyViewPagerAdapter(Context ctx, List<String> data) { this.ctx = ctx; this.data = data; } @Override public int getCount() { return data.size(); } @Override public Object instantiateItem(View collection, int position) { TextView view = new TextView(ctx); view.setText(data.get(position)); ((ViewPager)collection).addView(view); return view; } @Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Parcelable saveState() { return null; } @Override public void restoreState(Parcelable arg0, ClassLoader arg1) { } @Override public void startUpdate(View arg0) { } @Override public void finishUpdate(View arg0) { } } } 

30 Solutions collect form web for “ViewPager PagerAdapter不更新视图”

有几种方法来实现这一点。

第一种select更容易,但效率更低。

在你的PagerAdapter覆盖getItemPosition ,像这样:

 public int getItemPosition(Object object) { return POSITION_NONE; } 

这样,当你调用notifyDataSetChanged() ,视图分页器将删除所有的视图并重新载入。 因此获得了重载效果。

第二个选项, Alvaro Luis Bustamante(以前的alvarolb)build议 ,在instantiateItem()化一个新视图时,在instantiateItem() Tag setTag()方法。 然后,可以使用findViewWithTag()来查找要更新的视图,而不是使用notifyDataSetChanged()

第二种方法是非常灵活和高性能的。 荣誉alvarolb为原研究。

我不认为在PagerAdapter有任何一种错误。 问题是理解它是如何工作的有点复杂。 看看这里解释的解决scheme,从我的angular度来看,存在一个误解,因此对实例化视图的使用较差。

最近几天我一直在处理PagerAdapterViewPager ,我发现了以下几点:

notifyDataSetChanged()上的notifyDataSetChanged()方法只会通知ViewPager基础页面已经改变。 例如,如果您已经dynamic地创build/删除页面(添加或删除列表中的项目), ViewPager应该处理这个问题。 在这种情况下,我认为ViewPager确定是否应该使用getItemPosition()getCount()方法删除或实例化新视图。

我认为ViewPager ,在notifyDataSetChanged()调用后,它的子视图和getItemPosition()检查其位置。 如果对于子视图来说这个方法返回POSITION_NONE ,那么ViewPager理解视图已经被删除,调用destroyItem() ,并删除这个视图。

通过这种方式,如果只想更新页面的内容,则重写getItemPosition()总是返回POSITION_NONE是完全错误的,因为之前创build的视图将被销毁,并且每次调用notifyDatasetChanged()时都会创build新视图。 对于一些TextView ,似乎并不是那么错误,但是当您有复杂的视图时,如从数据库填充的ListViews,这可能是一个真正的问题,浪费资源。

所以有几种方法可以有效地改变视图的内容,而不必再次移除和实例化视图。 这取决于你想解决的问题。 我的方法是对instantiateItem setTag()方法中的任何实例化视图使用setTag() instantiateItem()方法。 因此,当您想要更改数据或使需要的视图无效时,可以调用ViewPager上的findViewWithTag()方法来检索先前实例化的视图,并根据需要修改/使用它,而无需删除/创build新视图每次你想更新一些值。

想象一下,例如,你有100个TextView的页面,你只想定期更新一个值。 使用前面解释的方法,这意味着您要在每次更新中删除和实例化100个TextView 。 它没有任何意义…

FragmentPagerAdapter更改为FragmentStatePagerAdapter

重写getItemPosition()方法并返回POSITION_NONE

最终,它将侦听查看寻呼机上的notifyDataSetChanged()

alvarolb给出的答案绝对是最好的办法。 基于他的回答,实现这一点的简单方法是简单地按位置存储活动视图:

 SparseArray<View> views = new SparseArray<View>(); @Override public Object instantiateItem(View container, int position) { View root = <build your view here>; ((ViewPager) container).addView(root); views.put(position, root); return root; } @Override public void destroyItem(View collection, int position, Object o) { View view = (View)o; ((ViewPager) collection).removeView(view); views.remove(position); view = null; } 

然后,通过覆盖notifyDataSetChanged方法,您可以刷新视图…

 @Override public void notifyDataSetChanged() { int key = 0; for(int i = 0; i < views.size(); i++) { key = views.keyAt(i); View view = views.get(key); <refresh view with new data> } super.notifyDataSetChanged(); } 

你实际上可以在instantiateItemnotifyDataSetChanged使用类似的代码来刷新你的视图。 在我的代码中,我使用完全相同的方法。

经过几个小时的挫折,同时尝试所有上述解决scheme来克服这个问题,也尝试了很多解决scheme,像这样的其他类似的问题, 这和这一切都失败了,我解决了这个问题,并使ViewPager破坏旧的Fragment和填充带有新Fragmentpager 。 我已经解决了这个问题,如下所示:

1)使ViewPager类扩展FragmentPagerAdapter ,如下所示:

  public class myPagerAdapter extends FragmentPagerAdapter { 

2)为存储titlefragmentViewPager创build一个Item,如下所示:

 public class PagerItem { private String mTitle; private Fragment mFragment; public PagerItem(String mTitle, Fragment mFragment) { this.mTitle = mTitle; this.mFragment = mFragment; } public String getTitle() { return mTitle; } public Fragment getFragment() { return mFragment; } public void setTitle(String mTitle) { this.mTitle = mTitle; } public void setFragment(Fragment mFragment) { this.mFragment = mFragment; } } 

3)ViewPager的构造ViewPager把我的FragmentManager实例存储在我的class ,如下所示:

 private FragmentManager mFragmentManager; private ArrayList<PagerItem> mPagerItems; public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) { super(fragmentManager); mFragmentManager = fragmentManager; mPagerItems = pagerItems; } 

4)创build一个方法,用新的数据重新设置adapter数据,直接删除fragment所有前一个fragment ,使adapter再次从新的列表中设置新的fragment ,如下所示:

 public void setPagerItems(ArrayList<PagerItem> pagerItems) { if (mPagerItems != null) for (int i = 0; i < mPagerItems.size(); i++) { mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit(); } mPagerItems = pagerItems; } 

5)从容器ActivityFragment不要用新数据重新初始化适配器。 使用新数据通过setPagerItems方法setPagerItems新数据,如下所示:

 ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>(); pagerItems.add(new PagerItem("Fragment1", new MyFragment1())); pagerItems.add(new PagerItem("Fragment2", new MyFragment2())); mPagerAdapter.setPagerItems(pagerItems); mPagerAdapter.notifyDataSetChanged(); 

我希望它有帮助。

有同样的问题。 对我来说,它扩展了FragmentStatePagerAdapter,并覆盖下面的方法:

 @Override public Parcelable saveState() { return null; } @Override public void restoreState(Parcelable state, ClassLoader loader) { } 

在OP提出问题两年半之后,这个问题仍然是一个问题。 显而易见的是,Google在这方面的优先级并不是特别高,所以我find了一个解决方法。 对我来说,重大的突破是找出问题的真正原因是什么(见本文接受的答案)。 一旦显示问题是任何活动页面没有正确刷新,我的解决方法是显而易见的:

在我的片段(页面)中:

  • 我从onCreateView中取出所有填充表单的代码,并将其放入一个名为PopulateForm的函数中,该函数可以从任何地方调用,而不是由框架调用。 这个函数试图使用getView获取当前的View,如果它是null,它就返回。 PopulateForm只包含显示的代码是非常重要的 – 所有其他创buildFocusChange监听器的代码仍然在OnCreate中
  • 创build一个布尔值,可以用作表示必须重新加载表单的标志。 我的是mbReloadForm
  • 如果设置了mbReloadForm,则覆盖OnResume()以调用PopulateForm()。

在我的活动中,我在哪里加载页面:

  • 在更改任何内容之前转到第0页。 我使用的是FragmentStatePagerAdapter,所以我知道最多只有两三页受到影响。 更改为第0页,确保我只有页面0,1和2有问题。
  • 在清除旧的清单之前,取其大小()。 这样你就知道这个bug有多less页面了。 如果> 3,减less到3 – 如果你使用一个不同的PagerAdapter,你必须看看你有多less页面处理(也许都是?)
  • 重新加载数据并调用pageAdapter.notifyDataSetChanged()
  • 现在,对于每个受影响的页面,通过使用pager.getChildAt(i)来查看页面是否处于活动状态 – 这会告诉您是否有视图。 如果是这样,请调用pager.PopulateView()。 如果不是,请设置ReloadForm标志。

在此之后,当您重新加载第二组页面时,错误仍然会导致一些显示旧数据。 但是,他们现在会刷新,你会看到新的数据 – 你的用户不会知道页面是不正确的,因为这种刷新将发生在他们看到页面之前。

希望这可以帮助别人!

更简单的方法是:使用FragmentPagerAdapter ,并将分页视图封装到碎片上。 他们确实得到更新

经过大量的search这个问题,我发现了一个非常好的解决scheme,我认为这是正确的方法。 从本质上讲,instantiateItem只在视图被实例化的时候才被调用,除非视图被销毁(这是当你重载getItemPosition函数返回POSITION_NONE时发生的情况)。 相反,你想要做的是保存创build的视图,并更新它们在适配器中,生成一个get函数,以便其他人可以更新它,或更新适配器(我的最爱)的设置function。

所以,在你的MyViewPagerAdapter中添加一个variables,如:

 private View updatableView; 

在你的instantiateItem中:

  public Object instantiateItem(View collection, int position) { updatableView = new TextView(ctx); //My change is here view.setText(data.get(position)); ((ViewPager)collection).addView(view); return view; } 

所以,这样,你可以创build一个函数来更新你的视图:

 public updateText(String txt) { ((TextView)updatableView).setText(txt); } 

希望这可以帮助!

我有一个类似的问题,我有四页,其中一页更新了其他三个意见。 我能够在当前页面的相邻页面上更新小部件(SeekBars,TextViews等)。 调用mTabsAdapter.getItem(position)时,最后两页将有未初始化的小部件。

为了解决我的问题,我在调用getItem(position)之前使用了setSelectedPage(index) getItem(position) 。 这将实例化页面,使我能够改变每个页面上的值和小部件。

在所有的更新之后,我将使用setSelectedPage(position)然后是notifyDataSetChanged()

您可以在主更新页面上的ListView中看到轻微的闪烁,但没有任何明显的迹象。 我还没有完全testing,但它确实解决了我眼前的问题。

为了防止任何人使用基于FragmentStatePagerAdapter的适配器(这将使ViewPager创build显示目的所需的最小页面,至多2我的情况),@ rui.araujo的覆盖getItemPosition在您的适配器不会造成重大浪费,但它仍然可以改进。

在伪代码中:

 public int getItemPosition(Object object) { YourFragment f = (YourFragment) object; YourData d = f.data; logger.info("validate item position on page index: " + d.pageNo); int dataObjIdx = this.dataPages.indexOf(d); if (dataObjIdx < 0 || dataObjIdx != d.pageNo) { logger.info("data changed, discard this fragment."); return POSITION_NONE; } return POSITION_UNCHANGED; } 

我只是发布这个答案,以防其他人发现它有用。 为了做同样的事情,我只是从兼容库中取得ViewPager和PagerAdapter的源代码,并在我的代码中进行编译(你需要清理所有的错误并导入你自己,但是完全可以这样做)。

然后,在CustomViewPager中,创build一个名为updateViewAt(int position)的方法。 视图本身可以从ViewPager类中定义的ArrayList mItem中获得(您需要为实例化项目设置视图的ID并将此ID与updateViewAt()方法中的位置进行比较)。 然后,您可以根据需要更新视图。

所有这些解决scheme都没有帮助我。 因此我find了一个setAdapter解决scheme:每次都可以设置setAdapter ,但这还不够。 你应该在更换适配器之前做这些:

 FragmentManager fragmentManager = slideShowPagerAdapter.getFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); List<Fragment> fragments = fragmentManager.getFragments(); for (Fragment f : fragments) { transaction.remove(f); } transaction.commit(); 

之后:

 viewPager.setAdapter(adapter); 

什么对我来说是去viewPager.getAdapter().notifyDataSetChanged();

并在适配器把你的代码更新getItemPosition里面的视getItemPosition这样

 @Override public int getItemPosition(Object object) { if (object instanceof YourViewInViewPagerClass) { YourViewInViewPagerClass view = (YourViewInViewPagerClass)object; view.setData(data); } return super.getItemPosition(object); } 

可能不是最正确的方法去做,但它的工作( return POSITION_NONE技巧导致我的崩溃,所以不是一个选项)

你可以dynamic更新所有的片段,你可以看到三个步骤。

在你的适配器中:

 public class MyPagerAdapter extends FragmentPagerAdapter { private static int NUM_ITEMS = 3; private Map<Integer, String> mFragmentTags; private FragmentManager mFragmentManager; public MyPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); mFragmentManager = fragmentManager; mFragmentTags = new HashMap<Integer, String>(); } // Returns total number of pages @Override public int getCount() { return NUM_ITEMS; } // Returns the fragment to display for that page @Override public Fragment getItem(int position) { switch (position) { case 0: return FirstFragment.newInstance(); case 1: return SecondFragment.newInstance(); case 2: return ThirdFragment.newInstance(); default: return null; } } // Returns the page title for the top indicator @Override public CharSequence getPageTitle(int position) { return "Page " + position; } @Override public Object instantiateItem(ViewGroup container, int position) { Object object = super.instantiateItem(container, position); if (object instanceof Fragment) { Fragment fragment = (Fragment) object; String tag = fragment.getTag(); mFragmentTags.put(position, tag); } return object; } public Fragment getFragment(int position) { Fragment fragment = null; String tag = mFragmentTags.get(position); if (tag != null) { fragment = mFragmentManager.findFragmentByTag(tag); } return fragment; }} 

现在在你的活动中:

 public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{ MyPagerAdapter mAdapterViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = (ViewPager) findViewById(R.id.vpPager); mAdapterViewPager = new MyPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(mAdapterViewPager); viewPager.addOnPageChangeListener(this); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { Fragment fragment = mAdapterViewPager.getFragment(position); if (fragment != null) { fragment.onResume(); } } @Override public void onPageScrollStateChanged(int state) { }} 

最后在你的片段中,有这样的东西:

 public class YourFragment extends Fragment { // newInstance constructor for creating fragment with arguments public static YourFragment newInstance() { return new YourFragment(); } // Store instance variables based on arguments passed @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } // Inflate the view for the fragment based on layout XML @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment, container, false); } @Override public void onResume() { super.onResume(); //to refresh your view refresh(); }} 

你可以在这里看到完整的代码。

感谢Alvaro Luis Bustamante。

总是返回POSITION_NONE很简单,但是效率不高,因为这会激发已经实例化的所有页面的实例化。

我创build了一个库ArrayPagerAdapter来dynamic改变PagerAdapters中的项目。

在内部,这个库的适配器只在必要时才返回getItemPosiition()上的POSITION_NONE

您可以像使用此库一样dynamic更改项目。

 @Override protected void onCreate(Bundle savedInstanceState) { /** ... **/ adapter = new MyStatePagerAdapter(getSupportFragmentManager() , new String[]{"1", "2", "3"}); ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter); adapter.add("4"); adapter.remove(0); } class MyPagerAdapter extends ArrayViewPagerAdapter<String> { public MyPagerAdapter(String[] data) { super(data); } @Override public View getView(LayoutInflater inflater, ViewGroup container, String item, int position) { View v = inflater.inflate(R.layout.item_page, container, false); ((TextView) v.findViewById(R.id.item_txt)).setText(item); return v; } } 

Thils库也支持由Fragments创build的页面。

这是一个可怕的问题,我很高兴提出一个很好的解决scheme; 简单,高效,有效!

见下面,代码显示使用一个标志来指示何时返回POSITION_NONE

 public class ViewPagerAdapter extends PagerAdapter { // Members private boolean mForceReinstantiateItem = false; // This is used to overcome terrible bug that Google isn't fixing // We know that getItemPosition() is called right after notifyDataSetChanged() // Therefore, the fix is to return POSITION_NONE right after the notifyDataSetChanged() was called - but only once @Override public int getItemPosition(Object object) { if (mForceReinstantiateItem) { mForceReinstantiateItem = false; return POSITION_NONE; } else { return super.getItemPosition(object); } } public void setData(ArrayList<DisplayContent> newContent) { mDisplayContent = newContent; mForceReinstantiateItem = true; notifyDataSetChanged(); } } 

感谢rui.araujo和Alvaro Luis Bustamante。 起初,我试图用rui.araujo的方式,因为它很容易。 它可以工作,但是当数据发生变化时,页面会明显重绘。 这是不好的,所以我试图用阿尔瓦罗·路易斯·布斯塔曼特的方式。 这是完美的。 这里是代码:

 @Override protected void onStart() { super.onStart(); } private class TabPagerAdapter extends PagerAdapter { @Override public int getCount() { return 4; } @Override public boolean isViewFromObject(final View view, final Object object) { return view.equals(object); } @Override public void destroyItem(final View container, final int position, final Object object) { ((ViewPager) container).removeView((View) object); } @Override public Object instantiateItem(final ViewGroup container, final int position) { final View view = LayoutInflater.from( getBaseContext()).inflate(R.layout.activity_approval, null, false); container.addView(view); ListView listView = (ListView) view.findViewById(R.id.list_view); view.setTag(position); new ShowContentListTask(listView, position).execute(); return view; } } 

而当数据发生变化时:

 for (int i = 0; i < 4; i++) { View view = contentViewPager.findViewWithTag(i); if (view != null) { ListView listView = (ListView) view.findViewById(R.id.list_view); new ShowContentListTask(listView, i).execute(); } } 

我发现这个问题很有意思。 我们可以使用FragmentStatePagerAdapterandroid.support.v4.app.FragmentStatePagerAdapter ),而不是使用FragmentPagerAdapter来保存内存中的所有片段。

两个适配器的实现是相同的。 所以,我们只需要改变“ 扩展FragmentStatePagerAdapter ”上的“ 扩展FragmentPagerAdapter

我有同样的问题,我的解决scheme是重写ViewPagerAdapter#getItemId(int position)

 @Override public long getItemId(int position) { return mPages.get(position).getId(); } 

默认情况下,此方法返回项目的位置。 我想, ViewPager检查itemId被更改,并重新创build页面,如果它是。 但是,即使页面实际上不同,未被覆盖的版本也返回与itemId相同的位置,并且ViewPager没有定义页面被replace,并且需要被重新创build。

要使用这个,每个页面都需要long id 。 通常情况下,它是唯一的,但我build议,在这种情况下,它应该是不同于以前的价值为同一页。 所以,在这里可以使用适配器中的连续计数器或随机整数(分布广泛)。

我认为这是比较一致的方式,而不是使用所提到的标签作为本主题的解决scheme。 但可能不是所有情况下。

我试过所有这些解决scheme都不适合我,因为我所有的观点都很复杂。 所以很难保存视图并更新视图。 如果你有一个简单的视图,只包含几个TextView或类似的东西,这很容易,这里发布的解决scheme工作。 但是,如果你像我的一样复杂的观点,需要改变整个片段,我认为这是不可能的。 我调查了ViewPager代码,看来ViewPager保留了旧的片段。 很容易实现它:从设备上search一些本机应用程序,实现轻扫,并进行testing将语言从英语改为阿拉伯语。 在这种情况下,它应该改变片段的顺序,因为阿拉伯语是一种RTL语言。 但是这种方式不行。

而不是返回POSITION_NONE并再次创build所有片段,您可以按照我在这里build议: dynamic更新ViewPager吗?

1.首先你必须在你的Pageradapter类中设置getItemposition方法2.你必须读取View Pager的Exact位置3.然后把这个位置作为你的新数据位置发送4.在setonPageChange里面写更新buttononclick监听器倾听者

该程序代码有点修改,只设置特定的位置元素

 public class MyActivity extends Activity { private ViewPager myViewPager; private List<String> data; public int location=0; public Button updateButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); data = new ArrayList<String>(); data.add("A"); data.add("B"); data.add("C"); data.add("D"); data.add("E"); data.add("F"); myViewPager = (ViewPager) findViewById(R.id.pager); myViewPager.setAdapter(new MyViewPagerAdapter(this, data)); updateButton = (Button) findViewById(R.id.update); myViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int i, float v, int i2) { //Toast.makeText(MyActivity.this, i+" Is Selected "+data.size(), Toast.LENGTH_SHORT).show(); } @Override public void onPageSelected( int i) { // here you will get the position of selected page final int k = i; updateViewPager(k); } @Override public void onPageScrollStateChanged(int i) { } }); } private void updateViewPager(final int i) { updateButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MyActivity.this, i+" Is Selected "+data.size(), Toast.LENGTH_SHORT).show(); data.set(i, "Replaced "+i); myViewPager.getAdapter().notifyDataSetChanged(); } }); } private class MyViewPagerAdapter extends PagerAdapter { private List<String> data; private Context ctx; public MyViewPagerAdapter(Context ctx, List<String> data) { this.ctx = ctx; this.data = data; } @Override public int getCount() { return data.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } @Override public Object instantiateItem(View collection, int position) { TextView view = new TextView(ctx); view.setText(data.get(position)); ((ViewPager)collection).addView(view); return view; } @Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Parcelable saveState() { return null; } @Override public void restoreState(Parcelable arg0, ClassLoader arg1) { } @Override public void startUpdate(View arg0) { } @Override public void finishUpdate(View arg0) { } } } 

I think I've made a simple way to notify of data set changes:

First, change a bit the way the instantiateItem function works:

  @Override public Object instantiateItem(final ViewGroup container, final int position) { final View rootView = mInflater.inflate(...,container, false); rootView.setTag(position); updateView(rootView, position); container.addView(rootView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); mViewPager.setObjectForPosition(rootView, position); return rootView; } 

for "updateView" , fill the view with all the data you wish to fill (setText,setBitmapImage,…) .

verify that destroyView works like this:

  @Override public void destroyItem(final ViewGroup container, final int position, final Object obj) { final View viewToRemove = (View) obj; mViewPager.removeView(viewToRemove); } 

Now, suppose you need to change the data, do it, and then call the next function on the PagerAdapter :

  public void notifyDataSetChanged(final ViewPager viewPager, final NotifyLocation fromPos, final NotifyLocation toPos) { final int offscreenPageLimit = viewPager.getOffscreenPageLimit(); final int fromPosInt = fromPos == NotifyLocation.CENTER ? mSelectedPhotoIndex : fromPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit : mSelectedPhotoIndex + offscreenPageLimit; final int toPosInt = toPos == NotifyLocation.CENTER ? mSelectedPhotoIndex : toPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit : mSelectedPhotoIndex + offscreenPageLimit; if (fromPosInt <= toPosInt) { notifyDataSetChanged(); for (int i = fromPosInt; i <= toPosInt; ++i) { final View pageView = viewPager.findViewWithTag(i); mPagerAdapter.updateView(pageView, i); } } } public enum NotifyLocation { MOST_LEFT, CENTER, MOST_RIGHT } 

For example if you wish to notify all of the views that are being shown by the viewPager that something has changed, you can call:

 notifyDataSetChanged(mViewPager,NotifyLocation.MOST_LEFT,NotifyLocation.MOST_RIGHT); 

而已。

For what it's worth, on KitKat+ it seems that adapter.notifyDataSetChanged() is enough to cause the new views to show up, provided that you've setOffscreenPageLimit sufficiently high. I'm able to get desired behavior by doing viewPager.setOffscreenPageLimit(2) .

I actually use notifyDataSetChanged() on ViewPager and CirclePageIndicator and after that I call destroyDrawingCache() on ViewPager and it works.. None of the other solutions worked for me.

if you want to solve Viewpager update problem check this project, it will solve your problem.

and more understand check that;

happy coding…

In my case every time that Fragment entered to @override onCreateView(…) i was restarting values so handle null or empty values like:

 if(var == null){ var = new Something(); } if(list.isEmpty()){ list = new ArrayList<MyItem>(); } if(myAdapter == null){ myAdapter = new CustomAdapter(); recyclerView.setAdapter(myAdapter); } // etc... 

Fragment class could enter to onCreateView every time we change and get back to the view from the UI at runtime.

I m using Tablayout with ViewPagerAdapter. For passing data between fragments or for communicating between fragments use below code which works perfectly fine and refresh the fragment when ever it appears. Inside button click of second fragment write below code.

 b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String text=e1.getText().toString(); // get the text from EditText // move from one fragment to another fragment on button click TabLayout tablayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); // here tab_layout is the id of TabLayout which is there in parent Activity/Fragment if (tablayout.getTabAt(1).isSelected()) { // here 1 is the index number of second fragment ie current Fragment LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext()); Intent i = new Intent("EDIT_TAG_REFRESH"); i.putExtra("MyTextValue",text); lbm.sendBroadcast(i); } tablayout.getTabAt(0).select(); // here 0 is the index number of first fragment ie to which fragment it has to moeve } }); 

below is the code which has to be written in first fragment (in my case) ie in receiving Fragment.

 MyReceiver r; Context context; String newValue; public void refresh() { //your code in refresh. Log.i("Refresh", "YES"); } public void onPause() { super.onPause(); LocalBroadcastManager.getInstance(context).unregisterReceiver(r); } public void onResume() { super.onResume(); r = new MyReceiver(); LocalBroadcastManager.getInstance(getActivity()).registerReceiver(r, new IntentFilter("EDIT_TAG_REFRESH")); } // this code has to be written before onCreateview() // below code can be written any where in the fragment private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { PostRequestFragment.this.refresh(); String action = intent.getAction(); newValue=intent.getStringExtra("MyTextValue"); t1.setText(newValue); // upon Referesh set the text } } 

I leave here my own solution, which is a workaround because seems as the problem is the FragmentPagerAdapter doesn't clean the previous fragments , you can be added to the ViewPager , in the Fragment Manager. So, I create a method to execute before add the FragmentPagerAdapter :

(In my case I never add more than 3 fragments, but you can use for example getFragmentManager().getBackStackEntryCount() and check all the fragments .

 /** * this method is solving a bug in FragmentPagerAdapter which don't delete in the fragment manager any previous fragments in a ViewPager. * * @param containerId */ public void cleanBackStack(long containerId) { FragmentTransaction transaction = getFragmentManager().beginTransaction(); for (int i = 0; i < 3; ++i) { String tag = "android:switcher:" + containerId + ":" + i; Fragment f = getFragmentManager().findFragmentByTag(tag); if (f != null) { transaction.remove(f); } } transaction.commit(); } 

I know it is a workaround because it will stop work if the way the framework is creating the tags change.

(currently "android:switcher:" + containerId + ":" + i )

Then the way to use it is after getting the container:

 ViewPager viewPager = (ViewPager) view.findViewById(R.id.view_pager); cleanBackStack(viewPager.getId()); 
  • 无限滚动图像ViewPager
  • 获取ViewPager的当前位置
  • IllegalStateException:使用ViewPager执行onSaveInstanceState后无法执行此操作
  • dynamic添加/删除页面到ViewPager
  • 在ViewPager中保存片段状态
  • IllegalStateException:<MyFragment>当前不在FragmentManager中
  • FragmentPagerAdapter和FragmentStatePagerAdapter之间的区别
  • 如何在ViewPager上进行循环滚动?
  • 在ViewPager中将一个片段replace为另一个片段
  • dynamic更新ViewPager?
  • 片段共享元素转换不适用于ViewPager