notifyDatasetChanged() listview gridview 不生效的一种加分享别人的遇到的情况

先列出我遇到的问题:
public class MyBaseAdapter extends BaseAdapter {
//...
private boolean[] selectBLs; //在构造中有初始化都为false

public void setActionMode(int pos) {
selectBLs[pos] = !selectBLs[pos];
}

getView(int position, View convertView, ViewGroup parent){
//...略
if (selectBLs[position] && color != 0) {
viewHolder.background.setBackgroundColor(color);
viewHolder.background.setAlpha(0.45f);
viewHolder.background.setVisibility(View.VISIBLE); //flag
} else {
viewHolder.background.setVisibility(View.GONE);
}
//...略
}

然后在activity/fragment 中使用

mAdapter.setActionMode(pos);
mAdapter.notifyDataSetChanged();

发现无法立刻刷新变化颜色,甚至在getView中打印log,能发现//flag的位置是走进去了的!需要滑动,直到点击过的被完全遮住,然后刷新回来的时候,就变化了!

解决办法:
mAdapter.setActionMode(pos);
mListView.setAdapter(mAdapter); //***重要!!!
mAdapter.notifyDataSetChanged(); //这句话都可有可无了!! 因为重新绑定了!!!(这里还有一个问题需要重新将位置刷新! 文章马上更新, 敬请期待)


原因分析:

首先我先引用别人博客的文章,http://m.blog.csdn.net/blog/u011290399/21654153
这个作为我的引子,来区分这位博主遇到的,与我的差别在哪里.关于Android中Adapter调用notifyDataSetChanged方法无效解析. 
在为ListView设置Adapter后,调用notifyDataSetChanged()方法改变数据,但是显示界面却无效果,总结以下几种原因:

1、未调用notifyDataSetChanged()方法,该错误很容易排除
2、数据集合中的数据没有改变,所以调用notifyDataSetChanged()方法后无效果,该错误也很容易排除
3、数据集合的指向改变了,所以调用notifyDataSetChanged()方法后无任何效果,该错误经常出现,并十分不容易排除。什么是数据集合的指向改变,看下面代码,各位看官就能明白了:

private ListView listView;
private List<String> list;
private ArrayAdapter<String> adapter;

private void setAdapter() {
// 实例化List集合对象
list = new ArrayList<String>();
list.add("Take Me To Your Heart");
list.add("My Heart Will Go On");
list.add("Yesterday Once More");
list.add("I Still Believe");
list.add("Just One Last Dance");
//flag0
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);//原来的flag1
listView.setAdapter(adapter);//绑定flag2
错误代码:
//改变List集合的指向
//改变了List集合的指向后,调用Adapter的notifyDataSetChanged()将无效果
list = new ArrayList<String>(); //*** 地址变了, 原来的那个flag1的位置新建的地址***/
list.add("Living To Love You");
adapter.notifyDataSetChanged();//*** 没门!不刷新! 是因为new了以后,内存地址是新的,list事实上已经是一个新的了!而你是之前flag2的位置绑定的adpater
//*** 这里的list跟之前的list扯不上关系,所以不会刷新

正确代码:
//解决方法
//清空原来的List数据集合,不可以重新实例化,只能添加新的集合列表
//错误多发生在查询数据库操作中
list.clear();//*** 这个解决方案这里,list是原来的地址,通过后面的list.addAll实现了,原来地址不变更新了而已.这是因为list这种数据类型比较像
//c++里面指针的概念,它在flag1的时候,以及adapter这个里面,绑定进去都是它的引用地址,所以是不变的,所以我们如果仅仅是改变它的元素就不会有问题,
//它的变化,能引起list的刷新

List<String> values = new ArrayList<String>();
values.add("Free Loop");
list.addAll(values);
adapter.notifyDataSetChanged();
}

   经过上面我添加的注释的分析,我们可以看出,如果错误代码的地方,我们在"没门"的地方,重新setAdapter一次肯定也是不行的,因为adapter是用之前的flag0位置那个时候的list的地址绑定的.

   所以必须在"没门"前面,使用list重新new新的adpater出来, 再setAdapter()一次才能OK.这是为什么呢?


   具体可以分析分析源码,现在就告诉大家, 如何识别会不会刷新的判断方法:
    

   前面说的地址的概念, 引用的博文的正确代码中,list只是清了清数据,重新填充了一下,但是他的地址是不变的,就好像房子还在那,装修家居变了下而已;而错误代码,已经重新买一套房子了位置变化了导致找不到了.


   回过头来分析我的代码,是有差别的.
我这里出问题的时候,"房子"是没有变化的.我在setActionMode调用的时候,改变的就是老的那个adpater"房子"里面的内容selectionBL[].这个时候调用notifyDatasetChanged(),因为我的代码逻辑的用意是通过selectionBL来控制某个view的变化,而这个不属于它监控的东西.

    在源码的逻辑中, 滑动没有完全遮住它的时候,mDataSetObserver已经监听好了,mRecycler是用目前显示的个数count来控制的.在没有划出的时候,它是不会变化的,只有滑出后,它的count会变化,会加载新的;再滑动回去,相当于新的,所以这就是为何我的现象出现"滑动到完全遮住,滑动回去才变化".

    而我的正确代码, 走一遍setAdapter(mAdpater), 重新绑定一次, 就能解决了.源码中有,setApdater就是将mDataSetObserver重新监听,数据就能立刻刷新.

    这时候,我们甚至都不需要notifyDatasetChanged()!!!(前提是你能把握住你的mAdapter确实已经被更新内容了!)


那么,notifyDataSetChanged()又是干什么呢?:

notifyDataSetChanged方法通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容。
public void notifyDataSetChanged ()

该方法内部实现了在每个观察者上面调用onChanged事件。每当发现数据集有改变的情况,或者读取到数据的新状态时,就会调用此方法。

public void notifyDataSetInvalidated ()

该方法内部实现了在每个观察者上面调用onInvalidated事件。每当发现数据集监控有改变的情况,比如该数据集不再有效,就会调用此方法。

 notifyDataSetInvalidated(),会重绘控件(还原到初始状态)
notifyDataSetChanged(),重绘当前可见区域

结论:

其实, 说了半天,可能也有人不明白,到底什么时候,我们更改了不变的"房子"的里面的"家居",nodifyDatasetChaged()就能生效呢?什么时候,又是,需要setAdapter一下呢?

总结下, 如果你的adpater的用法如我引用的博主那样,很明显数据是在外面管理的,而且地址是不变的,就能nodifyDatasetChaged;

所以我们写代码优先使用nodifyDatasetChaged来尝试;

如果nodifyDatasetChaged失败,停下来,想一想,你的mAdapter里面的一些东西,比如我的情况,是否确实被一些方法改变了数据.那么就setAdpater重新绑定一次;

如果还是失败, 说明重新setAdpater的mAdpater需要new了或者修改你的list等数据为不变化(即保证你的房子不变,即不乱new),因为你的数据可能地址已经变化!


另外附上一些其他的搜到的资料,说不定以后遇到其他的这些情况,2个博客中有4种情况,受益匪浅:

http://www.it165.net/pro/html/201403/10645.html
http://m.blog.csdn.net/blog/u011290399/21654153

猜你喜欢

转载自blog.csdn.net/jzlhll123/article/details/46526411