前言
在android应用开发过程中,我们需要是时刻注意保证应用程序的稳定和UI操作响应及时,不稳定或响应不及时会带来不好的用户体验。
为何要引入AsyncTask?
在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但一个进程中可以有多个线程。
在这些线程中,有一个线程叫做UI线程(也叫Main Thread),除了UI线程外的线程都叫子线程(Worker Thread)。UI线程主要负责控制UI界面的显示、更新、交互等。因此,UI线程中的操作延迟越短越好(流畅)。把一些耗时的操作(网络请求、数据库操作、逻辑计算等)放到单独的线程,可以避免主线程阻塞。
Android给我们提供了一种轻量级的异步任务类AsyncTask。该类中实现异步操作,并提供接口反馈当前异步执行结果及进度,这些接口中有直接运行在主线程中的(如 onPostExecute,onPreExecute等)。
API
百度翻译:
AsyncTask使适当的和易用的UI线程。这个类可以执行后台操作,并在用户界面上发布结果,而不必处理线程和/或处理程序。
AsyncTask的设计是围绕线程和处理器的一个辅助类,并不构成一个通用的线程框架。asynctasks应该用于短作业(最多。几秒钟)如果你需要保持线程运行很长一段时间,我们强烈建议您使用不同的java.util.concurrent包如执行API提供的,线程池和futuretask。
异步任务被定义为一个在后台线程上运行的运算,其结果是在用户界面上发布的。一个异步任务是由3的泛型类型定义为参数,过程和结果,和4个步骤,称为onpreexecute,doInBackground,onProgressUpdate和onpostexecute。
使用(API):
AsyncTask must be subclassed to be used. The subclass will override at least one method (
doInBackground(Params...)
), and most often will override a second one (
onPostExecute(Result)
.)
AsyncTask必须被子类继承使用。子类至少重写一个方法(doInBackground(Params...)),和最经常会重写第二个方法(onPostExecute(result))
AsyncTask的泛型
一个异步任务使用的三种类型如下:
1.Params,the type of the parameters sent to the task upon execution.(参数的类型发送到任务执行时。)
2.Progress,the type of the progress units published during the background computation.(后台计算过程中的进度单元类型。)
3.Result,the type of the result of the background computation.(后台运行的结果类型。)
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the typeVoid:(不是所有的参数都需要,不用时可以返回void类型)
源码:
AsyncTask内部逻辑主要有二部分:
1.与主线程交互,它内部实例化一个静态的自定义类InternalHandler,这个类是继承Handler的,在这个自定义类中绑定了一个叫做AsyncTaskResult的对象,每次子线程需要通知主线程,就调用sendToTarget发消息给handle,然后在handle的handleMessage中AsyncTaskResult根据消息的类型不同(如MESSAGE_POST_PROGRESS会更新进度条,MESSAGE_POST_CANCEL取消任务)而做这些操作都是在UI线程进行的。意味着,从子线程一旦需要和UI线程交互,内部自动调用了handler对象把消息放在主线程。(onProgressUpdate用于更新界面任务进度)
2.AsyncTask内部调用,虽然可以新建多个AsyncTask的子类实例,但是AsyncTask内部Handler和ThreadPoolExecutor都是static,这么定义是进程范围内共享的,所以AsyncTask控制着的进程范围内所有的子类实例,且该类的所有实例都共用一个线程池(serialExecutor和THREAD_POOL_EXECUTOR)和 另一个线程池Handler(InternalHandler)。
从代码可以看出,默认核心线程池的大小CORE_POOL_SIZE是根据Runtime.getRuntime().availableProcessors()获取设备的核数(比如你手机双核返回2),通常线程池的大小是默认期望的并发数。如:默认核心线程池大小5。意味着,如果线程池数量小于5,这时候新添加一个异步任务则会新建一个线程,如果数量大于等于5,这时候新建的异步任务会被放入缓存队列中等待。限制APP内AsyncTask并发的线程是有必要的。同时运行任务多,线程多,会导致短时间内手机内存被占完!
事实上,从android 3.0开始,每次新建异步任务的时候AsyncTask内部默认规则是按提交的先后顺序每次只运行一个异步任务。当然你也可以自己指定自己的线程池。
AsyncTask的工作原理
1.从他的execute方法开始分析,会调用executeOnExecutor();其中AsyncTask的onPreExecute方法是最先执行的,然后线程池开始执行。
2.从代码看,sDefaultExecutor实际上是一个串行的线程池,一个进程中所有的AsyncTask全部都在这个线程池中执行。从SerialExecutor的实现分析AsyncTask的排队执行的过程。
首先系统会把AsyncTask的参数封装为FutureTask对象,FutureTask是一个并发类,在这里它充当了Runnable的作用。
接着这个FutureTask会交给SerialExecutor的execute方法处理,execute方法会先把FutureTask对象插入到任务队列mTask中,如果这时没有正在活动的任务,那么就会调用SeriaExecutor的scheduleNext()类执行下个任务。同一个AsyncTask任务执行完后,AsyncTask会继续执行其他任务知道所有任务都被执行完,从这一点可以看出,默认情况下AsyncTask是串行执行的。
3.不行看得想吐了!W~u ~a~a.....
Note:
1.由于Handler需要和主线程交互,而Handler又是内置于AsyncTask中,所有AsyncTask的创建必须在主线程。
2.AsyncTaskResult的doInBackground(Params)方法执行异步任务运行在子线程中,其他方法运行在主线程中,可以操作UI组件。
3.不要手动的去调用AsyncTask的onPreExecute, doInBackground, publishProgress, onProgressUpdate, onPostExecute方法,这些都是由android系统自动调用的。
4.一个AsyncTask任务只能被执行一次。
5.运行中可以随时调用cancel(boolean)方法取消任务,如果成功调用isCancel()会返回true,并不会执行onPostExecute(),取而代之的是调用onCancelled()。从源码看,如果这个任务已经执行了这个时候调用cancel是不会真正的把task结束,而是继续执行,只不过改变的是执行之后的回调方法的onPostExecute还是onCancelled.