最近在利用ListView在做数据刷新的时候,遇到调用notifyDataSetChanged方法不管
用,于是打印了数据适配器中的数据发现确实数据是增加了,但是调用却没有生效。让我一直想去看看notifyDataSetChanged的工作原理以及实现流程,当然由于项目紧还是上网查了下,原来是我犯了非常低级的错误导致无法刷新。可是我却蒙在鼓里毫无察觉。下面我就讲讲我到底犯了什么“错”:
1.适配器
public class MyAdapter extends BaseAdapter { ArrayList<T> list; LayoutInflater inflater; public MyAdapter(Context context, ArrayList<T> list) { this.list = list; this.inflater = LayoutInflater.from(context); }
adapter = new MyAdapter(this, list); <span style="white-space:pre"> </span>listview.setAdapter(adapter);
List list = new ArrayList<T>(); ... // 刷新ListView void updateView(){ list = queryList(); adapter.notifyDataSetChanged(); } // 设置数据源 List queryList(){ ... }
可能这个图看上去有点乱,其实就是给BaseAdapter设置数据源一开始给是适配器设置了数据源1, 外部list的也是指向数据源1。
再后来调用updateView()方法的时候给list又重新设置了一个内存区,那么他就指向了数据源2,可是BaseAdapter中的List数据还是原来的数据源1。
当我们在调用notifyDataSetChanged()方法的时候不刷新也就很容易理解了。
正确的方式:
List list = new ArrayList<T>(); ... // 刷新ListView void updateView(){ list = list.addAll(queryList()); adapter.notifyDataSetChanged(); } // 设置数据源 List queryList(){ ... }
3.本质
其实说了这么多无非就是我们在大学学C语言的时候老师强调了无数遍的形参与实参的关系,以及指针的方面的东西,java虽然没有指针,但是引用也是可以类比指针的。引用的改变以及引用指向的内存中数据改变,这些问题都是我们要十分注意的。就好比StringBuffer和String的关系,当数据发生改变前者可以保值原有的引用而后者引用已经发生了改变,引用的改变其实也就是指向的内存空间的地址发生的改变。
总结:
其实讲了这么多可能有人觉得其实这不就是一个简单的引用错乱的问题吗,其实在实际开发中类的相互引用以及关系会变的错中复杂,可能一个小小的程序我们能很好的管理之间的调用,但是多了我们有时会很难把控。虽然java没有指针的概念,但是程序内存方面的知识还是不得不去研究一下的好,这样对于我们来说程序变得可控了。我也一直觉得c/c++都是有必要去学习的,其实不是去学语法什么的更多地是能了解底层。