谈起这个方法我相信基本每个接触一点Android开发的都用到过,但是好多时候并不是我们使用错了,而是无意之间的写法导致我们.notifyDataSetChanged()突然失去了效果,让我们摸不着头脑,下面根据自己的使用经验总结三种解决方法。
1.数据源没有更新,调用notifyDataSetChanged无效。
针对这个我们可以打断点看数据源发送变化没来解决。
2.adapter初始化时绑定的数据集合的地址所指向的数据没有发送改变。
这句话我们听着感觉蛮拗口的,下面我写一个例子分析分析:
//网络请求的数据
public List<String> mDatas== new ArrayList<>();;
/**
* 网络请求
*/
@Override
protected void initViews(Bundle savedInstanceState) {
MyAdapter mAdapter = new MyAdapter();
mListView.setAdapter(mAdapter);
dogetData();
}
private void dogetData() {
//----网络请求代码注释----------
mDatas=response.getResult();//*表示网络请求成功写法一*
for(int i=0;i<response.getResult().size();i++){ //*表示网络请求成功写法二*
mDatas.add(response.getResult().get(i));
}
//----------====
refreshUI();
}
public void refreshUI(){
//刷新适配器
mAdapter.notifyDataSetChanged();
}
/** 自定义的适配器 */
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
if(mDatas!=null){
return mDatas.size();
}
return 0;
}
@Override
public Object getItem(int position) {
if(mDatas!=null){
return mDatas.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = new TextView(getActivity());
tv.setText(mDatas.get(position));
return tv;
}
}
观察上面的网络请求部分的两种写法,首先我要说明的是写法一是错误的,写法二才是正确的。当我们无意之中写成写法一的这种形式就会造成adapter的适配器没有刷新,我们知道Java中基本类型和对象都是按值传递的,一个方法不能修改一个基本数据类型的参数,一个方法可以修改一个引用所指向的对象状态,但这仍然是按值调用而非引用调用,上面两种传递都进行了值拷贝的过程。
mDatas=response.getResult()
我们这个赋值是有问题的,这里我们新new了一个对象设置给了mDatas就是属于引用的值拷贝过程,这里属于浅拷贝Java拷贝概念,从堆内存中开辟一块空间给创造出来的对象,所以mDatas会重新指向这块新空间的地址而不指向原来初始化过程中指向的地址,所以
notifyDataSetChanged刷新的时候原地址上的数据源并没有发生任何变化,所以导致刷新失效,正确的写法应该是这样的:
for(int i=0;i<response.getResult().size();i++){
mDatas.add(response.getResult().get(i));
}
3.回调或者异步(线程调度)。
public List<NewsInfo > mDatas== new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//新的配置
.baseUrl(BASE_URL)
.build();
MyService service = retrofit.create(MyService.class);
service.news(userid, token,index) //获取Observable对象
.subscribeOn(Schedulers.newThread())//请求在新的线程中执行
.observeOn(Schedulers.io()) //请求完成后在io线程中执行
.doOnNext(new Action1<List<NewsInfo >>() {
@Override
public void call(List<NewsInfo > newsInfos) {
saveInfo(newsInfos);//保存信息到本地
// refreshUI(newsInfos); //位置一
}
})
.observeOn(AndroidSchedulers.mainThread())//最后在主线程中执行
.subscribe(new Subscriber<List<NewsInfo >>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
//请求失败
}
@Override
public void onNext(List<NewsInfo >newsInfos) {
//请求成功
refreshUI(newsInfos);//位置二
}
});
public void refreshUI(List<NewsInfo >newsInfos){
//刷新适配器
for (NewsInfo news : newsInfos) {
mDatas.add(news );
}
mAdapter.notifyDataSetChanged();
}
这里我们使用一段RxJava来简单清晰展示网络异步请求的过程,当我们在位置一的时候更新刷新肯定是不行的因为我们在子线程进行操作ui,但我们在位置二进行更新是可以的,但我们千万别忘了加上切换到ui线程或者使用handler的时候注意发送至主线程。