问题背景:项目中不断切换界面的过程中网络异步请求【耗时操作】,但是数据并未加载完成,此时界面中触碰事件时候,直接崩掉【频率低但存在】。
解决思路:监听异步操作完成后才让界面上的按钮可以响应单击【触碰】事件,数据在加载完成前,界面上的按钮触碰事件都应该被屏蔽掉。
实现:用原子操作记录每个异步线程执行开始和执行结束,最终通过标志位来判断所有的网路请求是否执行完,如果执行完、数据加载完毕,界面即可点击触碰操作。
【知识点】:原子操作--》AtomicInteger AtomicBoolean的运用。
操作图如下:
所有的网络都是异步请求,将第一个获取数据的地方开始计数,第一个网络请求开始的时候开始计时,然后执行完后就将计数器减一,计时器不断的加一和减一,计数器是原子操作保证数据安全性。那么执行完后统计计数器的数,那么当计数器为0的时候,就是说明请求完毕,数据加载完毕。
Code实现:在网络请求的地方开始计时【建立网络请求的构造方法也行】
this.doWorking = doWorking;
if (this.doWorking!=null) {
this.doWorking.beginThreadTask();
}
在网络请求数据完毕后:
if (this.doWorking!=null) { //在每次请求访问结束的时候,返回请求响应结果的时候将线程计数器减一
this.doWorking.endThreadTask();
}
具体在获取数据代码中调用回掉函数就行:
@Override
protected void initData() {
DoWorking.singleRunOk(isWorking, new DoWorking.doWorkingCallBack() {
@Override
public void run(DoWorking doWorking) {
//初始化 date2=new Date();获取用户做题时间
**
* 作者: on 2015/12/28 11:12
* 邮箱:jd_education@163.com
* * @Description: (原子操作:用户界面操作的一致性)
*/
public class DoWorking {
private AtomicInteger count = new AtomicInteger(0); //原子操作
private AtomicBoolean isWorking; //= new AtomicBoolean(false); //设置
//功能:
// 1. 顶层try住异常
// 2. 异常发送服务器日志
// 3. 一个线程运行时,别的线程直接返回
public static void singleRunOk(AtomicBoolean isWorking, doWorkingCallBack callback){
DoWorking dwork=new DoWorking();
dwork.isWorking=isWorking;
if (isWorking==null) {
try {
callback.run(dwork);//用来执行用户的业务逻辑
} catch (Exception e) {
SubmitErrorLogToServer.submitLog(e);
}
} else {
//理解isWorking.compareAndSet(false, true):如果实际值【isWorking】和期望值【false】相等就把实际值设置为更新值【true】,并返回true
//如果实际值isWorking和期望值不相等,那么就将实际值还是设为更新值,返回false
//总结:实际值最终为更新值,返回值代表的是逻辑是否走通
if(!isWorking.compareAndSet(false, true)){
return;
}
dwork.count.incrementAndGet(); //count+1【count用来计数】
try {
callback.run(dwork);//用来执行用户的业务逻辑
} catch (Exception e) {
if (0 == dwork.count.decrementAndGet()) {
isWorking.set(false); //如果退出到主程序就设为false
}
SubmitErrorLogToServer.submitLog(e);
}
if (0 == dwork.count.decrementAndGet()) {
isWorking.set(false);
}
}
}
//功能:
// 1. 顶层try住异常
// 2. 异常发送服务器日志
public static void safeRun(safeCallBack callback){
try {
callback.run();//用来执行用户的业务逻辑
} catch (Exception e) {
SubmitErrorLogToServer.submitLog(e);
}
}
public void beginThreadTask() {
count.incrementAndGet();
}
public void endThreadTask() {
if (0 == count.decrementAndGet()) {
if (isWorking!=null) {
isWorking.set(false);
}
}
}
public interface doWorkingCallBack { //回掉函数
void run(DoWorking dwork);
}
public interface safeCallBack { //initDa函数
void run();
}
总结:基本上用接口回掉即可实现效果,其实计数可以理解为记录当前请求线程的id即可,线程池里面还有没有线程。
理解下原子操作:AtomicInteger AtomicBoolean
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。