您的位置:首页 > 其它

关于AsyncTask的一个小疑问:为什么任务执行有延迟?

2017-08-21 10:06 691 查看
今天测试的妹子跟我说,公司的一个项目中发现有一个问题:在某些情况下文件浏览器的文件的加载速度非常慢,等待很长时间才显示!

首先,我的第一反应是,这不是软件的文件,一定是移动设备的问题。然后我就问测试妹子:你确定你没有在后台运行一堆软件的情况下测试么?

她十分肯定的回答:没有,只运行了XXX(公司的软件)。

先说明一下,我们公司的这个项目比较老,并没有用什么RxJava、EventBus这种主流框架。全是用什么AsyncTask+Broadcast这种原始的东西。这次的图片文件获取的过程就是用AsyncTask来获取的。让我仿佛回到了那种原始人用石头开荒的年代,被这种AsyncTask+Broadcast支配的恐惧可能老一点程序猿就深有感触。

所谓的某些情况是这样的流程:

首先,页面A 是有图片分析与捕捉的功能模块,可以分析或者捕捉图片。然后有一个按钮可以可以跳到页面B ,页面B 是文件浏览器用于浏览捕捉到的图片,浏览图片时,可以选择分析图片,此时是从页面B跳回页面A进行分析。

出现加载缓慢的操作是(红色标注是导致缓慢的操作):A->B->A->B。先在A捕捉图片,跳到B浏览所有捕捉到的图片,选好图片后然后再从B跳到A进行分析,最后在从A跳到B继续浏览图片。奇怪的地方就是第一次A->B是十分流畅的的,第二次A->B时却是十分缓慢!OMG,逻辑一模一样,而且第一次B->A时,我已经把B销毁了,理论上再次A->B,完全和第一次样。打印了B的生命周期方法确实是从头执行一遍的,证明每次操作都是新建一个B,为什么第二次会缓慢?

好背景交代完毕,疑问也提出来了,各位大牛如果知道是什么原因,希望您能给科普一下原因。

经过调试发现时是AsyncTask的方法执行有延迟了!代码是这样的:

private getImageStart(){
//do something
Log.i(TAG,"1");
new GetImageTask().execute();
}

private class GetImageTask extend AsyncTask<Void,Void,Void>{
@override
protected void onPreExecute(){
//do something
Log.i(TAG,"2");
}
@override
protected  Void doInBackground(void ...params){
Log.i(TAG,"3");
//do something
}
...
//other code
...
}

为了方便展示我使用了Log 1,2,3还代表,出现任务延迟在2->3这里,以下是日志截图:



这个两个方法的执行相隔了了4s之多!有时还更长!有人可能会说,是不是我在onPreExecute()执行了什么耗时的操作。实际上并没有,只有几个变量的赋值,而且第一次A->B很流畅啊。

然后,我就知道可能不是我代码的问题,也许是AsycTask出了说没问题。于是稍微瞧瞧源码。

当我们执行execute()方法时,在AsycTask内部是这么调用:



继续追下去看看executeOnExecutor():



我们看到了,实际上是调用sDefaultExecutor的execute的方法:



这个sDefaultExecutor又是什么?



其实是一个线性执行器,什么是线性执行,就是必须先完成上一个任务,才能执行下一个任务。我们看看这个东西的执行方法:



执行了onPreExecute()来到这里,这里先判断原来的任务是否结束,结束了再从队列中往下取一个出来执行。然后才是doInBackground()的内容。既然我的是2->3的时候发生延迟,那么和这里的逻辑逃脱不了关系。这里加了同步锁,也就是说必须等待上一个任务执行结束并且mActive==null,下一次执行请求才能进来。很有可能是因为这样才导致了我这段代码执行时间间隔太长。poll()方法都不用看了,很明显是线性执行导致的延迟了。但是为什么会有等待上一个任务执行结束的过程我就不得而知了。

大概了解过程之后,解决方法很快就出来了,我使用线程池多任务同步执行不就行了。然后修改代码进行测试:

private getImageStart(){
//do something
Log.i(TAG,"1");
//把这句注释掉
// new GetImageTask().execute();
//修
a315
改为
new GetImageTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
运行查看结果:



哈哈,完美解决,简直快如飞!

到这里大家会有个疑问:道理我都懂,可是明明是新建一个任务对象了,为什么第一次你执行的任务会影响到第二次任务的执行?

emmm....这个我就不知道了,需要大家去深究源码了。我也有这个疑问啊,而且我从B跳转到A时,我已经手动把AsyncTask中断了,资源也都释放了。理论上这个任务早就结束了,为什么会影响我也蒙蔽了。有空在研究研究,当然如果你知道了原因,不妨分享出来哦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐