AsyncTask总结

来源:互联网 发布:系统重装后c盘数据恢复 编辑:程序博客网 时间:2024/04/30 01:19

      首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

      Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。很多人说AsyncTask的设计主要是为了方便开发者在子线程中更新UI,这种说法其实不对的,AsyncTask是对线程池和Handler的封装,用户可以在相应的方法中处理耗时操作以及更新UI界面,而不需要考虑主线程与子线程的转化,因为AsyncTask已经帮你做好了封装,使得在线程池中进行耗时任务,在主线程中进行UI更新。

      AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载doInBackground方法)。

 

AsyncTask定义了三种泛型类型Params,Progress和Result。

Params 启动任务执行的输入参数。

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果。

使用过AsyncTask的同学都知道一个异步加载数据最少要重写以下这两个方法:

      doInBackground(Params…)后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

      onPostExecute(Result) 相当于Handler处理UI的方式,在这里面可以使用在doInBackground得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

onProgressUpdate(Progress…)  可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

onPreExecute()       这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

onCancelled()            用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

1)Task的实例必须在UI thread中创建;

2)execute方法必须在UI thread中调用;

3)不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

4)一个AsyncTask对象只能被执行一次,多次调用时将会出现异常;


AsyncTask不同版本的变化:

参见http://www.cnblogs.com/wanqieddy/p/3836480.html

AsyncTask内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask#execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。

(1)在API10以及以前的版本,AsyncTask内部维护这一个线程池,线程池中只有5个线程,当AsyncTask接到任务后,他会在线程池中并发执行这些任务,当任务数量大于5个时,先到的5个任务执行,其他任务等待,当有空闲线程时,在执行其他任务。而且多线程并发运行时,可能会出现资源抢夺的冲突,对于有些任务会出现异常,所以这种情况下就不能用AsyncTask来执行异步任务。

(2)在API11以及以后,android意识到了这些问题,从android3.0开始,对AsyncTask进行了一些调整,在AsyncTask中创建了两个线程池SERIAL_EXECUTORTHREAD_POOL_EXECUTOR)。

SERIAL_EXECUTOR实际上是一个串行的线程池,一个进程的所有AsyncTask全部在这个串行线程池中排队执行。

THREAD_POOL_EXECUTOR是一个经过配置的线程池,

A)核心线程数等于CPU核心数+1

B)线程池最大线程数量为CPU核心数*2+1

C)核心线程无超时机制,非核心线程闲置超时时间为1秒

D)任务队列最大是128

升级后的AsyncTask能做什么事情呢?

《1》 串行任务处理

采用execute来执行AsyncTask任务时,默认是采用SERIAL_EXECUTOR线程池进行任务排队,串行的调用THREAD_POOL_EXECUTOR线程池进行任务的处理。所以用此方法AsyncTask异步任务是串行的,当前一个任务完成了后第二个任务才能执行。

《2》并行任务处理

AsyncTask可以直接调用executeOnExecutor()来执行任务,这种方式允许任务并行处理。executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR””)是调用默认的THREAD_POOL_EXECUTOR线程池进行任务的并行处理,当人也可以自定义线程池,executeOnExecutor(Executors.newCachedThreadPool(),””)这种方式既可以采用用户自定义的线程池串行的执行异步任务。

java线程池ThreadPoolExecutor如何与AsyncTask()组合使用请参见:

http://www.cnblogs.com/linguanh/p/4563081.html?utm_source=tuicool&utm_medium=referral


asynctask虽然进行异步任务是很方便,可是在使用AsyncTask过程中我们应该注意一些问题:

asynctask的缺陷和问题:http://blog.csdn.net/goodlixueyong/article/details/45895997

在开发中,可以使得用户避免直接使用类和来处理后台操作,适用于需要异步处理数据并将数据更新到界面上的情况。适用于后台操作只有几秒的短时操作。但是本身存在很多糟糕的问题,如果使用中不注意,将会影响程序的健壮性。

1、生命周期

       很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁。然而事实并非如此。AsyncTask会一直执行, 直到doInBackground()方法执行完毕。然后,如果 cancel(boolean)被调用, 那么onCancelled(Result result) 方法会被执行;否则,执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不存在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确地取消

       另外,即使我们正确地调用了cancle() 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。

2、内存泄漏

        如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

3、结果丢失

       屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

4、并行还是串行

      在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)。




0 0
原创粉丝点击