我正在使用兼容性库中的ViewPager。 我已经巧妙地让它显示了几个我可以翻阅的视图。

但是,我很难弄清楚如何使用一组新视图更新ViewPager。

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

没有任何帮助,文本视图与原始数据保持不变。

更新:我做了一个小测试项目,我几乎能够更新视图。 我将粘贴下面的课程。

然而,似乎没有更新的是第二个视图,“B”仍然存在,按下更新按钮后应显示“Y”。

public class ViewPagerBugActivity extends Activity {private ViewPager myViewPager;private List<String> data;@Overridepublic 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() {@Overridepublic 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;}@Overridepublic int getCount() {return data.size();}@Overridepublic Object instantiateItem(View collection, int position) {TextView view = new TextView(ctx);view.setText(data.get(position));((ViewPager)collection).addView(view);return view;}@Overridepublic void destroyItem(View collection, int position, Object view) {((ViewPager) collection).removeView((View) view);}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}@Overridepublic Parcelable saveState() {return null;}@Overridepublic void restoreState(Parcelable arg0, ClassLoader arg1) {}@Overridepublic void startUpdate(View arg0) {}@Overridepublic void finishUpdate(View arg0) {}}
}

#1楼

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使用类似的代码来刷新视图。 在我的代码中,我使用完全相同的方法。


#2楼

一种更简单的方法:使用FragmentPagerAdapter ,并将分页视图包装到片段上。 他们确实得到了更新


#3楼

我实际上在ViewPagerCirclePageIndicator上使用了notifyDataSetChanged() ,之后我在ViewPager上调用了destroyDrawingCache()并且它正常工作..其他解决方案都没有为我工作。


#4楼

为了防止任何人使用基于FragmentStatePagerAdapter的适配器(这将使ViewPager创建显示目的所需的最小页面,对于我的情况最多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;
}

#5楼

而不是返回POSITION_NONE并再次创建所有片段,您可以按照我的建议进行操作: 动态更新ViewPager?


#6楼

1.首先,你必须在Pageradapter类中设置getItemposition方法2.你必须阅读View Pager的精确位置3.然后将该位置作为新位置的数据位置发送4.在setonPageChange中写入更新按钮onclick listener倾听者

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

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() {@Overridepublic void onPageScrolled(int i, float v, int i2) {//Toast.makeText(MyActivity.this, i+"  Is Selected  "+data.size(), Toast.LENGTH_SHORT).show();}@Overridepublic void onPageSelected( int i) {// here you will get the position of selected pagefinal int k = i;updateViewPager(k);}@Overridepublic void onPageScrollStateChanged(int i) {}});
}private void updateViewPager(final int i) {  updateButton.setOnClickListener(new OnClickListener() {@Overridepublic 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;}@Overridepublic int getCount() {return data.size();}@Overridepublic int getItemPosition(Object object) {return POSITION_NONE;}@Overridepublic Object instantiateItem(View collection, int position) {          TextView view = new TextView(ctx);view.setText(data.get(position));((ViewPager)collection).addView(view);            return view;}@Overridepublic void destroyItem(View collection, int position, Object view) {((ViewPager) collection).removeView((View) view);}@Overridepublic boolean isViewFromObject(View view, Object object) {return view == object;}@Overridepublic Parcelable saveState() {return null;}@Overridepublic void restoreState(Parcelable arg0, ClassLoader arg1) {}@Overridepublic void startUpdate(View arg0) {}@Overridepublic void finishUpdate(View arg0) {}
}
}

#7楼

所有这些解决方案都没有帮助我。 因此我找到了一个有效的解决方案:你可以每次都设置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);

#8楼

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

在我的片段(页面):

  • 我从onCreateView中获取了填充表单的所有代码,并将其放在一个名为PopulateForm的函数中,该函数可以从任何地方调用,而不是通过框架调用。 此函数尝试使用getView获取当前View,如果为null,则返回。 重要的是PopulateForm只包含显示的代码 - 创建FocusChange监听器之类的所有其他代码仍在OnCreate中
  • 创建一个布尔值,可以用作表示必须重新加载表单的标志。 我的是mbReloadForm
  • 如果设置了mbReloadForm,则重写OnResume()以调用PopulateForm()。

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

  • 在更改任何内容之前转到第0页。 我正在使用FragmentStatePagerAdapter,所以我知道最多会影响两到三页。 更改为第0页可确保我在第0,1和2页上遇到问题。
  • 在清除旧列表之前,请选择它的大小()。 这样您就可以知道有多少页面受到了bug的影响。 如果> 3,将其减少到3 - 如果您使用的是另一个PagerAdapter,则必须查看您需要处理的页数(可能全部?)
  • 重新加载数据并调用pageAdapter.notifyDataSetChanged()
  • 现在,对于每个受影响的页面,使用pager.getChildAt(i)查看页面是否处于活动状态 - 这会告诉您是否有视图。 如果是这样,请调用pager.PopulateView()。 如果没有,请设置ReloadForm标志。

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

希望这有助于某人!


#9楼

经过挫折小时,尝试所有上述解决方案来克服这个问题,也试图像其他类似的问题,很多解决方案这个 , 这个和这个 ,所有与我没能解决这个问题,使ViewPager摧毁旧的Fragment ,并填写具有新Fragmentpager 。 我已经解决了以下问题:

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

 public class myPagerAdapter extends FragmentPagerAdapter {

2)ViewPager创建一个Item,用于存储titlefragment ,如下所示:

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)创建一个方法,通过直接从fragmentManager本身删除所有先前的fragment来重新设置adapter数据与新数据,使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使用新数据设置新数据,如下所示:

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();

我希望它有所帮助。


#10楼

我想我已经通过一种简单的方式来通知数据集的变化:

首先,改变一下instantiateItem函数的工作方式:

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

对于“updateView”,用您要填充的所有数据填充视图(setText,setBitmapImage,...)。

验证destroyView的工作方式如下:

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

现在,假设您需要更改数据,执行此操作,然后调用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
}

例如,如果您希望通知viewPager显示的所有视图已更改的内容,您可以调用:

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

而已。


#11楼

FragmentPagerAdapter更改为FragmentStatePagerAdapter

覆盖getItemPosition()方法并返回POSITION_NONE

最终,它将侦听视图寻呼机上的notifyDataSetChanged()


#12楼

对我viewPager.getAdapter().notifyDataSetChanged();viewPager.getAdapter().notifyDataSetChanged();

并在适配器中放置代码以更新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技巧导致我崩溃所以不是一个选项)


#13楼

对于它的价值,在KitKat +上,似乎adapter.notifyDataSetChanged()足以导致新视图显示,前提是你已经setOffscreenPageLimit足够高的setOffscreenPageLimit 。 我可以通过viewPager.setOffscreenPageLimit(2)获得所需的行为。


#14楼

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

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

#15楼

您可以动态更新所有片段,您可以分三步查看。

在您的适配器中:

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 viewrefresh();}}

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

谢谢Alvaro Luis Bustamante。


#16楼

始终返回POSITION_NONE很简单,但效率有点低,因为这会唤起已经实例化的所有页面的实例化。

我创建了一个库ArrayPagerAdapter来动态更改PagerAdapters中的项目。

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

您可以使用此库动态更改项目,如下所示。

@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);}@Overridepublic 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创建的页面。


#17楼

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

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

public class ViewPagerAdapter extends PagerAdapter
{// Membersprivate 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@Overridepublic 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();}}

#18楼

感谢rui.araujo和Alvaro Luis Bustamante。 起初,我尝试使用rui.araujo的方式,因为它很容易。 它可以工作,但是当数据发生变化时,页面会重新显示。 这很糟糕所以我尝试使用Alvaro Luis Bustamante的方式。 这是完美的。 这是代码:

@Override
protected void onStart() {super.onStart();
}private class TabPagerAdapter extends PagerAdapter {@Overridepublic int getCount() {return 4;}@Overridepublic boolean isViewFromObject(final View view, final Object object) {return view.equals(object);}@Overridepublic void destroyItem(final View container, final int position, final Object object) {((ViewPager) container).removeView((View) object);}@Overridepublic 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();}
}

#19楼

我正在使用Tablayout和ViewPagerAdapter。 为了在片段之间传递数据或者在片段之间进行通信,请使用下面的代码,这些代码可以正常工 在内部按钮点击第二个片段写下面的代码。

b.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String text=e1.getText().toString(); // get the text from EditText// move from one fragment to another fragment on button clickTabLayout tablayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); // here tab_layout is the id of TabLayout which is there in parent Activity/Fragmentif (tablayout.getTabAt(1).isSelected()) { // here 1 is the index number of second fragment i-e current FragmentLocalBroadcastManager 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 i-e to which fragment it has to moeve}});

下面是必须用第一个片段(在我的例子中)写入的代码,即接收片段。

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 fragmentprivate class MyReceiver extends BroadcastReceiver {@Overridepublic 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}
}

#20楼

我发现这个问题很有意思。 我们可以使用FragmentStatePagerAdapterandroid.support.v4.app.FragmentStatePagerAdapter ),而不是使用FragmentPagerAdapter来保存内存中的所有片段,每当我们选择它时,重新加载片段。

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


#21楼

我想,我已经掌握了ViewPager的逻辑。

如果我需要刷新一组页面并根据新数据集显示它们,我会调用notifyDataSetChanged() 。 然后,ViewPager对getItemPosition()进行了多次调用,将Fragment作为Object传递给它。 此片段可以来自旧数据集(我想要丢弃),也可以来自新数据集(我想要显示)。 所以,我重写了getItemPosition() ,我必须以某种方式确定我的Fragment是来自旧数据集还是来自新数据集。

在我的情况下,我有一个2窗格布局,左侧窗格中有顶部项目列表,右侧是滑动视图(ViewPager)。 所以,我在我的PagerAdapter中存储了一个链接到我当前的顶级项目,并且还存储了每个实例化页面片段内的链接。 当列表中选定的顶部项目发生更改时,我将新的顶级项目存储在PagerAdapter中并调用notifyDataSetChanged() 。 在重写的getItemPosition()中,我将我的适配器中的顶部项目与我的片段中的顶部项目进行比较。 只有当它们不相等时,我才会返回POSITION_NONE。 然后,PagerAdapter重新实例化已返回POSITION_NONE的所有片段。

注意。 存储顶部项ID而不是引用可能是一个更好的主意。

下面的代码片段有点示意,但我从实际工作的代码中进行了调整。

public class SomeFragment extends Fragment {private TopItem topItem;
}public class SomePagerAdapter extends FragmentStatePagerAdapter {private TopItem topItem;public void changeTopItem(TopItem newTopItem) {topItem = newTopItem;notifyDataSetChanged();}@Overridepublic int getItemPosition(Object object) {if (((SomeFragment) object).getTopItemId() != topItem.getId()) {return POSITION_NONE;}return super.getItemPosition(object);}
}

感谢所有以前的研究人员!


#22楼

这适用于所有像我这样的人,需要从服务(或其他后台线程)更新Viewpager,并且没有任何提议有效:经过一些logchecking我意识到,notifyDataSetChanged()方法永远不会返回。 getItemPosition(Object object)被称为all ends,无需进一步处理。 然后我在父PagerAdapter类的文档中找到(不在子类的文档中),“数据集更改必须在主线程上发生,并且必须以对notifyDataSetChanged()的调用结束”。 因此,本例中的工作解决方案是(使用FragmentStatePagerAdapter和getItemPosition(Object object)设置为返回POSITION_NONE):

然后调用notifyDataSetChanged():

runOnUiThread(new Runnable() {@Overridepublic void run() {pager.getAdapter().notifyDataSetChanged();}});

#23楼

我有同样的问题,我的解决方案是使用FragmentPagerAdapter覆盖FragmentPagerAdapter#getItemId(int position)

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

默认情况下,此方法返回项目的位置。 我想ViewPager检查itemId已更改并仅在重新创建页面时才会显示。 但是,即使页面实际上不同,not-overriden版本也返回与itemId相同的位置,并且ViewPager没有定义该页面被替换为一个并且需要重新创建。

要使用此功能,每个页面都需要long id 。 通常情况下,它应该是唯一的,但我建议,对于这种情况,它应该与同一页面的先前值不同。 因此,可以在适配器或随机整数(具有广泛分布)中使用连续计数器。

我认为这是更一致的方式而不是使用在本主题中提到的视图标签。 但可能不适用于所有情况。


#24楼

您可以像这样在Viewpager上添加寻呼机转换

myPager.setPageTransformer(true, new MapPagerTransform());

在下面的代码中,当寻呼机滚动时,我在运行时更改了我的视图颜色

public class MapPagerTransform implements ViewPager.PageTransformer {public void transformPage(View view, float position) {LinearLayout  showSelectionLL=(LinearLayout)view.findViewById(R.id.showSelectionLL);if (position < 0) {showSelectionLL.setBackgroundColor(Color.WHITE);}else if (position >0){showSelectionLL.setBackgroundColor(Color.WHITE);}else {showSelectionLL.setBackgroundColor(Color.RED);}}
}

#25楼

下面的代码对我有用。

创建一个扩展FragmentPagerAdapter类的类,如下所示。

public class Adapter extends FragmentPagerAdapter {private int tabCount;
private Activity mActivity;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private int container_id;
private ViewGroup container;
private List<Object> object;public Adapter(FragmentManager fm) {super(fm);
}public Adapter(FragmentManager fm, int numberOfTabs , Activity mA) {super(fm);mActivity = mA;mFragmentManager = fm;object = new ArrayList<>();mFragmentTags = new HashMap<Integer, String>();this.tabCount = numberOfTabs;
}@Override
public Fragment getItem(int position) {switch (position) {case 0:return Fragment0.newInstance(mActivity);case 1:return Fragment1.newInstance(mActivity);case 2:return Fragment2.newInstance(mActivity);default:return null;}}@Override
public Object instantiateItem(ViewGroup container, int position) {Object object = super.instantiateItem(container, position);if (object instanceof Fragment) {Log.e("Already defined","Yes");Fragment fragment = (Fragment) object;String tag = fragment.getTag();Log.e("Fragment Tag","" + position + ", " + tag);mFragmentTags.put(position, tag);}else{Log.e("Already defined","No");}container_id = container.getId();this.container = container;if(position == 0){this.object.add(0,object);}else if(position == 1){this.object.add(1,object);}else if(position == 2){this.object.add(2,object);}return object;
}@Override
public void destroyItem(ViewGroup container, int position, Object object) {super.destroyItem(container, position, object);if (object instanceof Fragment) {Log.e("Removed" , String.valueOf(position));}
}@Override
public int getItemPosition (Object object)
{   int index = 0;if(this.object.get(0) == object){index = 0;}else if(this.object.get(1) == object){index = 1;}else if(this.object.get(2) == object){index = 2;}else{index = -1;}Log.e("Index" , "..................." + String.valueOf(index));if (index == -1)return POSITION_NONE;elsereturn index;
}public String getFragmentTag(int pos){return "android:switcher:"+R.id.pager+":"+pos;
}public void NotifyDataChange(){this.notifyDataSetChanged();
}public int getcontainerId(){return container_id;
}public ViewGroup getContainer(){return this.container;
}public List<Object> getObject(){return this.object;
}@Override
public int getCount() {return tabCount;
}}

然后在您创建的每个Fragment中创建一个updateFragment方法。 在此方法中,您可以更改片段中需要更改的内容。 例如,在我的例子中,Fragment0包含一个GLSurfaceView,它根据.ply文件的路径显示一个3d对象,所以在我的updateFragment方法中,我改变了这个ply文件的路径。

然后创建一个ViewPager实例,

viewPager = (ViewPager) findViewById(R.id.pager);

和一个Adpater实例,

adapter = new Adapter(getSupportFragmentManager(), 3, this);

然后这样做,

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);

然后在类中你初始化上面的Adapter类并创建了一个viewPager,每次你想要更新你的一个片段(在我们的例子中是Fragment0)时使用以下内容:

adapter.NotifyDataChange();adapter.destroyItem(adapter.getContainer(), 0, adapter.getObject().get(0)); // destroys page 0 in the viewPager.fragment0 = (Fragment0) getSupportFragmentManager().findFragmentByTag(adapter.getFragmentTag(0)); // Gets fragment instance used on page 0.fragment0.updateFragment() method which include the updates on this fragmentadapter.instantiateItem(adapter.getContainer(), 0); // re-initialize page 0.

该解决方案基于Alvaro Luis Bustamante建议的技术。


#26楼

有几种方法可以实现这一目标。

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

在你的PagerAdapter覆盖getItemPosition ,如下所示:

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

这样,当您调用notifyDataSetChanged() ,视图寻呼机将删除所有视图并重新加载它们。 因此,获得了重载效果。

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

第二种方法非常灵活,性能高。 感谢alvarolb的原创研究。


#27楼

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

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


#28楼

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

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

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

您可以在主更新页面上的ListView中看到轻微的闪烁,但没有什么值得注意的。 我没有彻底测试它,但它确实解决了我的直接问题。


#29楼

我不认为PagerAdapter存在任何类型的错误。 问题是了解它的工作原理有点复杂。 看看这里解释的解决方案,从我的角度来看,存在误解,因此对实例化视图的使用很差。

最近几天我一直在使用PagerAdapterViewPager ,我发现了以下内容:

notifyDataSetChanged()的方法PagerAdapter只会通知ViewPager底层页面发生了变化。 例如,如果您已动态创建/删除页面(在列表中添加或删除项目),则ViewPager应该处理此问题。 在这种情况下,我认为ViewPager确定是否应使用getItemPosition()getCount()方法删除或实例化新视图。

我认为ViewPagernotifyDataSetChanged()调用之后会获取它的子视图并使用getItemPosition()检查它们的位置。 如果对于子视图,此方法返回POSITION_NONE ,则ViewPager理解视图已被删除,调用destroyItem()并删除此视图。

这样,如果您只想更新页面的内容,则覆盖getItemPosition()以始终返回POSITION_NONE是完全错误的,因为以前创建的视图将被销毁,并且每次调用notifyDatasetChanged()时都会创建新的视图。 对于一些TextView来说似乎没有那么错,但是当你有复杂的视图时,比如从数据库填充的ListViews,这可能是一个真正的问题而且浪费资源。

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

想象一下,例如,你有100个页面,100个TextView ,你只想定期更新一个值。 使用前面介绍的方法,这意味着您将在每次更新时删除并实例化100个TextView 。 它没有任何意义...


#30楼

经过大量的搜索,我发现了一个非常好的解决方案,我认为这是解决这个问题的正确方法。 本质上,instantiateItem仅在实例化视图时被调用,除非视图被销毁,否则永远不会被调用(这是当您重写getItemPosition函数以返回POSITION_NONE时发生的情况)。 相反,你想要做的是保存创建的视图,并在适配器中更新它们,生成一个get函数,以便其他人可以更新它,或者更新适配器的set函数(我最喜欢的)。

因此,在MyViewPagerAdapter中添加一个变量,如:

private View updatableView;

你的instantiateItem中的一个:

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

所以,通过这种方式,您可以创建一个更新视图的功能:

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

希望这可以帮助!

ViewPager PagerAdapter未更新视图相关推荐

  1. oracle 修改序列末值,当ViewModel值更改时,用户界面未更新

    我已经创建了示例应用程序来演示我的问题: 一 TextView 和A Button ,文本视图可见性绑定到 viewModel.bar 我想让按钮切换 查看模型 当单击时,用户界面也会得到更新. 然而 ...

  2. MySQL可更新视图

    可更新视图是指通过视图,来更新.插入.删除基本表中的数据.视图是一个虚拟表,即对视图的更新,实质上是更新基表.但是视图的构造很多时候是由多个表连接查询,以及结合聚合函数,分组过滤等等定义的.对于这类的 ...

  3. 全球 PC 应用程序有半数已过期未更新

    开发四年只会写业务代码,分布式高并发都不会还做程序员?   据防病毒软件 Avast 官方公布的一份 PC 安全报告,显示了全球 PC 上安装的应用软件有55%是过期软件,恐增加 PC 的风险.数据显 ...

  4. java或者jsp中修复会话标识未更新漏洞

    appscan扫描出来的. 1. 漏洞产生的原因: AppScan会扫描"登录行为"前后的Cookie,其中会对其中的JSESSIONOID(或者别的cookie id依应用而定) ...

  5. 数据改动,更新视图,类似于vue

    //当数据改变时,更新视图,和vue的有点类似let obj = { name:{ name:'ll' }, age:12,}let arr = [1,2,3];//针对数组的写法//当需要改变原型对 ...

  6. vue数组操作不更新视图问题

    vue 观察数组的变异方法 更新视图 push() pop() shift() unshift() splice(i,n,arr) sort(xx) reverse() ex: app.book.pu ...

  7. vue数组变化视图_vue数组操作不更新视图问题(示例代码)

    vue 观察数组的变异方法 更新视图 push() pop() shift() unshift() splice(i,n,arr) sort(xx) reverse() ex: app.book.pu ...

  8. ZK的实际应用:MVVM –以编程方式更新视图

    在前两篇文章中,我们使用ZK的MVVM功能来: 将数据加载到表中 使用表单绑定保存数据 我们已经看到,用注解@NotifyChange()装饰方法时,在执行完成后,将向Binder通知VM属性的更改, ...

  9. rails4 ajax 例子,Ajax和Rails 4:创建实例变量并更新视图而不刷新

    我有一个部分的coaching_notes索引和一个用于创建备注的表单.我想创建一个教练笔记,并进行部分更新而不刷新页面.我收到一个未知动作错误:CoachingNotesController无法找到 ...

最新文章

  1. opencv + python3 利用ros 的 cv_bridge 传送图像消息的一种替代方法
  2. leetcode算法题--解码方法★
  3. Linux系统编程---17(条件变量及其函数,生产者消费者条件变量模型,生产者与消费者模型(线程安全队列),条件变量优点,信号量及其主要函数,信号量与条件变量的区别,)
  4. android判断主线程_android中从子线程切换到主线程,但是显得代码很臃肿,请教大牛是怎么自定义的?...
  5. Solaris 中的环境变量
  6. Redis轻松实现秒杀系统
  7. HTML5开发和web前端开发的区别与联系?
  8. 【curl】【php】curl报错,错误代码77,CURLE_SSL_CACERT_BADFILE (77)解决方法
  9. CouchBase简单介绍
  10. java多个点求连线_实现简单的粒子连线
  11. web资源优化-图片篇(一)
  12. 项目经理如何做好授权管理?
  13. 工作9年的程序员几点感受
  14. 2022年江西省建筑三类人员(企业主要负责人A证)练习题及答案
  15. 10 个快速提升技术水平的方法
  16. Excel技巧—如何快速批量删除空行
  17. Vue实例基础5 (vue 条件渲染与列表渲)
  18. ASP.NET 在 Windows Azure 环境中使用基于 SQLServer 的 Session
  19. 熬夜整理,五万字长文总结 C/C++ 知识点
  20. CefSharp的ChromiumWebBrowser截出来的图片是空白

热门文章

  1. Trim or Discard or Unmap
  2. 樊正伦教授的养生之道中医文化与养生之---调情志
  3. 机器学习项目实战----泰坦尼克号获救预测(二)
  4. python第三十一课--递归(3.递归的弊端)
  5. angularJS指令
  6. hastable与dictionary
  7. C# 如何在空间运行时调整控件位置和大小
  8. Zabbix 4.0监控PHP-Fpm Pools
  9. java学习,不定期更新~
  10. 关于layui中lay-verify=required无效的解决办法