编者:李国帅
qq:9611153 微信lgs9611153
时间:2019-02-20
在android编程的时候,经常会遇到连续点击或ListView下拉,激发事件后向服务器请求数据,等返回后进行数据处理的情况。
为了避免这种情况,一般想到的就是计算两次事件的时间间隔,第二次激发事件的时候直接跳过。网上实现这种方法的方式很多,不过万变不离其宗。类似如下:
这种方法并不是完美的方案,弊端有很多:
1,两次事件之间的间隔多少才算合适呢?不同的情景都不一样,使用统一的时间间隔明显不合适。
2,如果事件激发后需要向后台请求数据,那么网络的好坏和服务器响应时间都会成为制约因素。
3、有的解决方法使用全局静态的时间间隔,那么就会造成所有的事件变成的相关事件,如果两个事件无关而被快速激发的时候,就会造成后面的事件无法执行,从而导致业务逻辑问题。
4、对于ListView RecyclerView这样的控件一次下拉可能多次激发”加载更多”事件,如果网络迟延大于事件间隔,有可能导致重复从同一位置请求的事件。
Android studio
故而,我认为判断是否激发第二次事件,应该根据第一次激发事件的结果而判断。
如果是普通的二次激发,可以直接丢弃;如果是允许的二次激发,那么应该根据第一次的事件响应来判断。
比如listview的下拉事件,明显是可以进行快速重复调用加载事件的。
这就需要添加一个判断标记,当响应之后恢复标记表示可以重新开始激发事件。
示意如下:
//是否正在获取数据
private boolean isLoadingData = false;
初始调用
isLoadingData = false;
loadData(curPos);
需要的时候调用
loadData(curPos);
调用之前需要先进行判断
private void loadData(int iPos) {
if (onGetDataListener != null && !isLoadingData) {
isLoadingData = true;
onGetDataListener.getData(iPos);//真正调用接口获取网络数据
} else {
SxbLog.e("listAdapter","loadData isLoadingData == " + isLoadingData);
}
}
public void afterGetData() {//调用结束后
//设置数据
//列表中信息数量增加,curPos改变
isLoadingData = false;
}
|
下面列举一个曾经使用过的方案。
1、使用简单变量,控制多次调用retrofit调用
private boolean isAdding = false;// 正在添加
private void addData() {
if (isAdding) {
return;
}
isAdding = true;
//....
JsonDataCheck.printJsonObj(1, in);
MyServiceI service = MyApplication.getServiceI(MyServiceI.WAITTIMEOUT_SENCONDS);
Call model = service.addData(in);//通过retrofit2传统方法获取数据
model.enqueue(new Callback() {
public void onResponse(Call call, Response response) {
//数据处理
isAdding = false;
}
|
2、使用锁定类改造
public class ServiceOperate {
//...
//避免多次操作
private static Integer taskRefreshing = 0;
public static void setLock(int value)
{
synchronized (taskRefreshing) {
taskRefreshing = value;
}
}
public static boolean isLock()
{
synchronized (taskRefreshing) {
if (taskRefreshing == 1) {
return true;
}
}
return false;
}
}
打开页面的时候初始化
protected void onCreate(Bundle savedInstanceState) { ServiceOperate.setLock(0);//避免以前被锁定
|
异步查询
private void addData(final int newStatus) {
//...
if (ServiceOperate.isLock()) {//查询之前判断是否正在查询
return;
}
ServiceOperate.setLock(1);//锁定
//...
MyServiceI service = MyApplication.getServiceI(MyServiceI.WAITTIMEOUT_SENCONDS);
Call model = service.addData(in);
model.enqueue(new Callback() {
public void onResponse(Call call, Response response) {
//数据处理
ServiceOperate.setLock(0);//查询后解锁
}
3、使用list中的变量,不在外部使用锁定。
可以把锁定放在xlistview的setDataUpdating函数中
@SuppressLint("HandlerLeak")
private final Handler mHandler = new Handler();
class ixListListener implements IXListViewListener {
@Override
public void onRefresh() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!mListView.getDataUpdating()) {
mListView.setDataUpdating(true);//查询的时候设置
refreshContent();
}
}
}, 50);
}
@Override
public void onLoadMore() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (!mListView.getDataUpdating()) {
mListView.setDataUpdating(true);
updateList();// 追加数据。
}
}
}, 50);
}
}
查询完成后复原
private void updateList() {
if (readTag == 2) {
refreshListView();//条件不具备复原
return;// 数据添加完毕
}
//...
JsonDataCheck.printJsonObj(1, in);
MyServiceI service = MyApplication.getServiceI(MyServiceI.WAITTIMEOUT_SENCONDS);
Call model = service.QueryList(in);
model.enqueue(new Callback() {
public void onResponse(Call call, Response response) {
refreshListView();//查询后复原,间接调用mListView.setDataUpdating(false);
当然了,这里只是一个简单的没有太多花哨的技术。