AsyncTaks , HandlerThread , IntentService 小结
线程是操作系统调度的最小单元,又是一种受限制的系统资源,即线程不可能无限次地生产,并且线程的创建和消耗都有相应的开销,当系统中存在大量的线程是,系统会通过时间片轮转的方式调度每个线程,分为两种
- 主线程: 处理和界面相关的事情
- 子线程:用于好事的操作
如果线程中频繁创建和消耗线程,这种做法不是很高效,可以采用线程池,一个线程池会缓存一定数量的线程,通过线程池可以避免频繁创建和消耗线程所带来的系统开销。主要通过 Executor 来派生特定类型的线程池。
扮演线程的角色有很多,包括 AsyncTask 和 IntentService ,同时 HandlerThread 也是一种特殊的线程
AsyncTaks
AsyncTask 底层封装了线程池和 Handler ,主要用于开发者可以使用在子线程中更新 UI, 是一种轻量级的异步任务类,并不适合进行特别耗时的后台任务,
AsyncTaks 的一些限制
- AsyncTask的类必须在主线程中加载。
- AsyncTask的对象必须在主线程中创建
- execute方法必须在 UI 线程中调用
- 不要在程序中直接调用onPreExecute().onPosteExecute(), doInBackground 和 onProgressUpdate 方法
- 一个 AsyncTask 对象只能执行一次,即只能调用一次 execute() 方法,否则会报运行时异常
- 在1.6 之前是串行,在3.0 之前是采用线程池并行,在3.0 之后,为避免并发错误,又采用串行执行任务。但是可以同 executeOnExecutor 方法并行执行任务
AsyncTask 的工作原理
从 execute 方法分析
public final AsyncTask<Params, Progress , Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress , Result> executeOnExecutor(Executor exec,Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
又以上源码可知
- execute 方法调用的是 executeOnExecutor() 方法
- 因为 ececute 方法是在主线程中调用的,所以 onPreExecute() 方法确实是在主线程中执行的,然后才开始执行线程池
- sDefaultExecutor看源码可知是一个串行的线程池,一个进程中的所有 AsyncTack 全部都放入到这个线程池中排队执行。
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();//执行 Runnalbe 任务
} finally {
//执行下一个 AsyncTask 任务
scheduleNext();
}
}
});
if (mActive == null) {//没有活动中的 AsyncTask 任务
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
从 SerialExecutor 的实现可以分析 AsyncTask 的排队执行过程
- 把 AsyncTask 的 Params 参数封装为 FutureTask 对象这个并发类
- 把 FutureTask 对象交给 SerialExecutor 的 exctute() 方法执行
- 如果这个时候没有活动中的 AsyncTask 任务,那么就调用 scledulNext() 方法执行下一个 AsyncTask 任务,
- 如果有,则会执行完这个任务之后,执行 scledulNext()
- 两个线程池 sDefaultExecutor 和THREAD_POOL_EXECUTOR
- THREAD_POOL_EXECUTOR 是用来执行任务,
- sDefaultExecutor 只是为了任务的排队。
- 一个Handler InternalHandler
InternalHandler 用于将执行环境从线程池切换到主线程
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
postResultIfNotInvoked(get());
...
}
};
}
THREAD_POOL_EXECUTOR.execute(mActive) 会执行到 FutureTask 的run()-> callable.call() 这个 callable 就是创建 FutureTask 的 mWorke 对象。于是就执行到了 WorkerRunnable 的 call() 中
在 AsyncTask 的构造函数中,我们可以看到在 mWorker 的 call 方法中,
- 将 mTaksInvoked 设置为 true ,表示当前任务已经被调用,
- 然后执行 doInbackgroud() 方法,
- 接着将其返回值传递给 postResult() 方法,
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
从上面三段代码可以看出
- postResult() 其实就是通过 sHandler 发送一个 MESSAGE_POST_RESULT 消息
- sHandler 是一个静态的 Handler 对象,这样就能保证 sHandler 是在主线程中的,因为静态成员会在加载类的时候进行初始化
- MESSAGE_POST_RESULT这个消息类型在 sHandler 中最后执行了result.mTask.finish()方法,而result.mTask.其实就是一个 AsyncTask 对象,即最后执行到了 AsyncTask 的 finish 方法中,
- 在 finish 方法中可以看到,如果取消了,就执行取消的方法,否则执行 onPostExecute() 方法,这样就又在主线程中了。
整个 AsyncTask 的过程也就分析完毕了
总结一下。调用链就是:
AsyncTask.execute()->AsyncTask.executeOnExecutor()->AsyncTask.onPreExecute()
->sDefaultExecutor.execute(FutureTask)->把 FutureTask 插入到 mTasks 队列中
->AsyncTask.SerialExecutor.scheduleNext(FutureTask)
->FutureTask.run()->WorkerRunnable.call()->AsyncTask.doInBackground()
->AsyncTask.postResult()->通过 Handler 发送消息到主线程
->FutureTask.finish() ->AsyncTask.onPostExecute()
HandlerThread
HandlerThread 底层使用的是线程,是一种只用消息循环的线程,他的内部可以使用handler 是一种可以使用 Handler 的 Thread ,实现很简单,
public class HandlerThread extends Thread {
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
}
- 是个 Thread 不假,但是在 run() 方法中,竟然Looper.prepare(),还Looper.loop(),新建一个 Looper 对象,并且已经启动 loop 开始循环。这就有点意思了。 所以使用上 HandlerThread 和普通的 Thread 不一样,无法执行后台常见的操作,只能处理新消息。因为Looper.loop()是一个死循环
- 由于 HandlerThread 的 run 方法是一个无线循环,因此当明确不需要使用 HandlerThread 的时候,通过 quit 或者 quitSafety 方法来终止线程的执行。
- 普通 Thread 主要在 run() 中执行耗时操作。 HandleThread 内部建立消息机制。需要外接通过 handler 消息通知 HandlerThread 执行的具体任务。
IntentService
- 一种特殊的 Service ,继承 Service 并且是一个抽象类 public abstract class IntentService extends Service
- 可用于执行后台耗时任务,当任务执行后会自动停止。
- 由于是一个 service ,所以优先级比单纯的线程要高,适合执行一些优先级高的后台任务,
使用方法
- 创建一个 IntentService 的子类。复写其中的 onHandleIntent() 方法,在这里进行耗时的操作
- startService(intent) 这样就行了,简单。可是为啥 IntentService 就能直接处理耗时操作呢,普通的 Service 还需要在 onStartCommand() 中再开线程才行。
还是看 IntentService 的源码吧
public abstract class IntentService extends Service {
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags , int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
protected abstract void onHandleIntent(Intent intent);
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
}
- 在 onCreate() 的时候,就创建一个 HandlerThread 对象,然后启动,拿到这个 HandlerThread 的 Looper 对象,这才是关键。创建一个继承 Handler 的类 ServiceHandler ,把得到的子线程的 Looper 对象传进去。
- 是 Service , startService() 后,肯定就会执行到了 onStartCommand() 方法,里面执行了 onStart() 的。这个时候关键来了,把 intent 封装成 Message 然后通过 ServiceHandler 送出去。 之前我们讲过,创建 Handler 的时候需要一个 Looper 对象,这个 Looper 对象属于哪个线程,那么 Handler 就会把消息发送给那个线程。 ServiceHandler 创建的时候传递的是子线程的 Looper 对象,那么会把消息发送到这个子线程中去。所以 handleMessage() 就肯定是在 HanderThread 这个线程中执行的。
- handleMessage()中调用了 onHandleIntent() ,将 Intent 对象传递给 onHandleIntent() 处理,这个 Intent 的内容和外界的startService(Intent)的内容是完全一致, onHandleIntent() 是需要我们实现的方法,可以进行执行耗时操作的方法。因为它就是执行在子线程的。并
- handleMessage() 最后会 stopSelf(msg.arg1),把自己停掉。这么智能啊。
- onBind()中返回 null ,所以不适合使用 bindService() 的方式使用IntentService()
所以 IntentService 有以下特点:
- 继承 Service ,所以优先级比较高
- 内部创建了一个 HandlerThread 和 ServiceHandler ,可以做一些耗时操作
- 当任务执行完成后, IntentService 自动停止,不需要我们手动结束
- 如果多次启动 IntentService ,使用串行方式,依次执行 onHandlerIntent() ,执行完自动结束。那么每个耗时的操作都会消息的形式发生到消息队列中。
既已览卷至此,何不品评一二: