最近闲来开发一个自己游戏公会的小应用,成员介绍模块的实现用到了Recyclerview,从后台获取成员的详细信息然后Recyclerview展示。实现下拉刷新数据时,遇到了一个问题:后台数据更新后,下拉一次数据没有变化,再刷一次才显示到最新数据。最初的代码如下:
public Handler memberRequestHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constant.HANDLER_REQUEST_MEMBERS:
mList = (List<MemberInfo>) msg.obj;
break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
if (null == contentView) {
contentView = inflater.inflate(R.layout.fragment_member, container, false);
refreshLayout = (SwipeRefreshLayout) contentView.findViewById(R.id.refreshLayout);
recyclerView = (RecyclerView) contentView.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
initRefreshView();
if(adapter == null){
adapter = new MemberAdapter(mContext);
recyclerView.setAdapter(adapter);
}
onRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mThread = new GetMemberItemThread(memberRequestHandler);
mThread.start();
adapter.setData(mList);
adapter.notifyDataSetChanged();
refreshLayout.setRefreshing(false);
}
};
refreshLayout.setOnRefreshListener(onRefreshListener);
refreshLayout.post(new Runnable() {
@Override
public void run() {
refreshLayout.setRefreshing(true);
onRefreshListener.onRefresh();
}
});
} else {
((ViewGroup) contentView.getParent()).removeView(contentView);
}
return contentView;
}
其中,GetMemberItemThread类是获取后台成员信息的线程,在其run方法中handler将结果通过msg传递到主线程。上面的代码是在handleMessage中得到mList,然后在onrefresh中为adapter设置数据,最后调用adapter.notifyDatasetChanged()更新数据,这样就出现前面所述的问题。上面代码看起来没什么问题,GetMemberItemThread线程start后执行run方法获取到memberInfo,然后hanlder获取到赋值给mList,最后在onfresh中设置给adapter。想了半天也没有想到哪里出问题,后来调试发现GetMethodItemThread启动后并没有像想象中那样立即运行run方法,而是进入到onCreateView中,并且mList的大小为0!网上查了资料得知线程start后只是表示线程处于就绪状态,它首先做了创建线程等一系列工作,然后调用行的run()方法,run()方法只是一个类中的普通方法,直接执行和普通的方法没有什么两样。这样mList的size为0的原因就好解释了,onRefresh方法调用后,handler的msg从send到handle中间有一个时间,这是不可人为操控的,受很多因素影响。数据刷新延迟的原因就是mList还没赋值前就已经调用了setAdater。解决这一问题的方法就是将mList的赋值和设置adapter一起放在handleMessage中,这样就保证了mList的数据取得之后才设置adapter。更改后的代码如下:
public Handler memberRequestHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constant.HANDLER_REQUEST_MEMBERS:
mList = (List<MemberInfo>) msg.obj;
//将下面onRefresh()中的adapter设置数据添加到此处
adapter.setData(mList);
adapter.notifyDatasetChanged();
refreshLayout.setRefreshing(false);
break;
}
}
};
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
if (null == contentView) {
contentView = inflater.inflate(R.layout.fragment_member, container, false);
refreshLayout = (SwipeRefreshLayout) contentView.findViewById(R.id.refreshLayout);
recyclerView = (RecyclerView) contentView.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
initRefreshView();
if(adapter == null){
adapter = new MemberAdapter(mContext);
recyclerView.setAdapter(adapter);
}
onRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mThread = new GetMemberItemThread(memberRequestHandler);
mThread.start();
//此处的adapter设置数据去掉,并把refreshLayout.setRefresh(false)
//移动到上面,这样保证加载数据完成后,加载动画才结束。
}
};
refreshLayout.setOnRefreshListener(onRefreshListener);
refreshLayout.post(new Runnable() {
@Override
public void run() {
refreshLayout.setRefreshing(true);
onRefreshListener.onRefresh();
}
});
} else {
((ViewGroup) contentView.getParent()).removeView(contentView);
}
return contentView;
}
希望对大家有所帮助,如果有什么理解不对的地方,欢迎指正。