android viewpager listview问题

当前位置: >
> 追溯源码解决android疑难有关问题1-Viewpager之notifyDataSetChanged无刷新
追溯源码解决android疑难有关问题1-Viewpager之notifyDataSetChanged无刷新
lala2009 & at
追溯源码解决android疑难问题1--Viewpager之notifyDataSetChanged无刷新最近项目结束,搞了一次代码分享。其中一位同学分享了一下自己在解决问题过程中的一些心得体会,感觉受益匪浅。整理出来,分享给大家。
建议使用自己编译的android os和虚拟机,这样就可以调试android系统中的任何组件。简单说来,深入android源码,去寻找解决问题的答案。这事儿说起来简单,实际做起来还是有些难度的。我也曾经尝试着去看过,没看一会儿就晕了。
所以还是有针对性的去看源码,效率会高一些。
废话不多说,先看第一个示例。
Viewpager在调用notifyDataSetChanged()时,界面无刷新。
相信很多做过Viewpager的同学肯定遇到过这个问题,这个是bug还是android就是如此设计的,我们不做讨论。总之,它确实影响我们功能的实现了。
可能不少同学选择为Viewpager重新设置一遍适配器adapter,达到刷新的目的。但是这种方法在大多数情况下,是有问题的。
追踪源代码:
为什么调用数据更新的方法,Viewpager却没有更新呢,我们跟进该方法的源代码看一下。
  首先查看适配器调用的super.notifyDataSetChanged(),该方法调到抽象基类PagerAdapter.notifyDataSetChanged()中:
* This method should be called by the application if the data backing this adapter has changed
* and associated views should update.
public void notifyDataSetChanged() {
mObservable.notifyChanged();
& 注释里说到,当附加在适配器上的数据发生变化时,应该调用该方法刷新数据。该方法调用了一个mObservable .notifyChanged();
我们继续跟进这个方法,进入DataSetObservable类中,发现这样一段代码:
* Invokes {@link DataSetObserver#onChanged} on each observer.
* Called when the contents of the data set have changed.
The recipient
* will obtain the new contents the next time it queries the data set.
public void notifyChanged() {
synchronized(mObservers ) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers .size() - 1; i &= 0; i--) {
mObservers.get(i).onChanged();
  这都不是重点,重点我们来看这个mObservers的类型是一个抽象类DataSetObserver,里面只有两个未实现的方法, 我们来看一下都有谁使用了这个抽象类呢,快捷键 ctrl + alt + H ,在众多的调用者当中,我们发现了Viewpager的身影:
  进入viewpager,我们终于找到了viewpager中控制数据变更的重点方法dataSetChanged ,这个方法如下:
  void dataSetChanged () {
// This method only gets called if our observer is attached, so mAdapter is non-null.
boolean needPopulate = mItems .size() & mOffscreenPageLimit * 2 + 1 &&
mItems.size() & mAdapter.getCount();
int newCurrItem = mCurI
boolean isUpdating =
for (int i = 0; i & mItems.size(); i++) {
final ItemInfo ii = mItems .get(i);
final int newPos = mAdapter.getItemPosition(ii.object );
if (newPos == PagerAdapter.POSITION_UNCHANGED ) {
if (newPos == PagerAdapter.POSITION_NONE) {
mItems.remove(i);
if (!isUpdating) {
mAdapter.startUpdate( this);
isUpdating =
mAdapter.destroyItem( this, ii.position , ii.object);
needPopulate =
if (mCurItem == ii.position ) {
// Keep the current item in the valid range
newCurrItem = Math. max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
needPopulate =
if (ii.position != newPos) {
if (ii.position == mCurItem ) {
// Our current item changed position. Follow it.
newCurrItem = newP
ii. position = newP
needPopulate =
if (isUpdating) {
mAdapter.finishUpdate( this);
Collections. sort(mItems, COMPARATOR);
if (needPopulate) {
// Reset o populate will recompute them.
final int childCount = getChildCount();
for (int i = 0; i & childC i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.isDecor ) {
lp. widthFactor = 0.f;
setCurrentItemInternal(newCurrItem, false, true);
requestLayout();
重点看这样一行代码:
  final int newPos = mAdapter.getItemPosition(ii.object );
if (newPos == PagerAdapter.POSITION_UNCHANGED ) {
仔细看了一下这段代码的大意,官方的解释是:
  Called when the host view is attempting to determine if an item's position has changed. Returns POSITION_UNCHANGED if the position of the given item has not changed or POSITION_NONE if the item is no longer present in the adapter.
The default implementation assumes that items will never change position and always returns POSITION_UNCHANGED.
  意思是如果item的位置如果没有发生变化,则返回POSITION_UNCHANGED。如果返回了POSITION_NONE,表示该位置的item已经不存在了。默认的实现是假设item的位置永远不会发生变化,而返回POSITION_UNCHANGED
解决方案:
所以我们可以尝试着修改适配器的写法,覆盖getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。
具体代码如下:
  class SearchAdapter extends PagerAdapter {
private int mChildCount = 0;
public void notifyDataSetChanged() {
mChildCount = getCount();
super.notifyDataSetChanged();
public int getItemPosition(Object object)
if ( mChildCount & 0) {
mChildCount --;
return POSITION_NONE;
return super.getItemPosition(object);
大家可以尝试一下,欢迎拍砖。
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-android viewpager进度条跟随页面滑动 - 下载频道
- CSDN.NET
&&&&android viewpager进度条跟随页面滑动
android viewpager进度条跟随页面滑动
功能就是可以随时跟随滑动,页面滑到一半,那么进度条也会滑到一半。
博客地址 http://blog.csdn.net/qq_
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
您可能还需要
移动开发下载排行求教ViewPager的使用问题。
ViewPager有个初始化方法instantiateItem。在里面对分页的组件进行操作,但现在我有3页,第一页是一个ListView,第二页是个ListView,第三页暂不管。我一进入ViewPager的页面后,初始化方法直接会给我初始化好第一页和第二页。也就是position0和1。但我想实现当点第一页的某个ListView的item后,第二页的ListView可以刷新,是变化的。请问如何介入?或者怎样实现呢,贴上我的代码,一个是在第一页的ListView中,点击事件里重写第二个ListView。一个方法是发一个信息,都失败了。代码可能有点乱。为了方便大家看所以都用的内部方法没有实现接口。
其中ListViewTotal和ListVIewSecond是成员的。代码没有贴出ViewPager第三页的内容
public class MyPagerAdapter extends PagerAdapter {
public List&View& mListV
public MyPagerAdapter(List&View& mListViews) {
this.mListViews = mListV
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView(mListViews.get(arg1));
public void finishUpdate(View arg0) {
public int getCount() {
return mListViews.size();
public Object instantiateItem(final View view, int position) {
switch (position) {
System.out.println("初始化第1个页面");
listViewTotal = (ListView) mListViews.get(position)
.findViewById(R.id.listView_total);
PoemTypeAdapter typeAdapter = new PoemTypeAdapter(
HomeActivity.this, listTotal);
listViewTotal.setAdapter(typeAdapter);
listViewTotal.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView&?& arg0, View arg1,
int position, long arg3) {
// TODO Auto-generated method stub
listSecond = new TotalTypeService()
.getAllTotalType(listTotal.get(position)
.getId() + "");
PoemTypeAdapter secondAdapter = new PoemTypeAdapter(
HomeActivity.this, listSecond);
listViewSecond.setAdapter(secondAdapter);
System.out.println("走点击事件");
Message msg = new Message();
msg.arg1 = 2;
handler.sendEmptyMessage(msg.arg1);
System.out.println("发送消息成功");
flagUploadSecond =
mPager.setCurrentItem(1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("初始化第2个页面");
listViewSecond = (ListView) mListViews.get(position)
.findViewById(R.id.listView_second);
final PoemTypeAdapter secondAdapter = new PoemTypeAdapter(
HomeActivity.this, listSecond);
listViewSecond.setAdapter(secondAdapter);
listViewSecond
.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView&?& arg0,
View arg1, int position, long arg3) {
if (position == 0) {
mPager.setCurrentItem(2);
handler = new Handler() {
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.arg1 == 2) {
System.out.println("已接收消息");
secondAdapter.notifyDataSetChanged();
System.out.println("刷新页面成功");
该问题被发起重新开启投票
投票剩余时间:
之前被关闭原因:
该问题被发起删除投票
投票剩余时间:
距离悬赏到期还有:
参与关闭投票者:
关闭原因:
该问题已经被锁定
锁定原因:()
保护原因:避免来自新用户不合宜或无意义的致谢、跟帖答案。
该问题已成功删除,仅对您可见,其他人不能够查看。
问题已解决,我的解决方案是在第二个页面中加入Handler接受信息,因为一上来就会初始化第一和第二两个页面的,所以你可以放心的在第二个页面中去new Handler。第一个页面中的ListView加点击事件,发送消息,第二个页面接受到消息后对自己的适配器setDataChange。刷新即可。一种方案不可行。就是在第一个页面的点击事件中,重新构造第二个页面的ListView
不是您所需,查看更多相关问题与答案
德问是一个专业的编程问答社区,请
后再提交答案
关注该问题的人
共被浏览 (7915) 次

我要回帖

更多关于 viewpager 循环 的文章

 

随机推荐