Android 消息机制
1 概述
Android 的消息机制主要是指 Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工作过程。
Android 应用是事件驱动的,每个事件都会转化为一个系统消息,即 Message 。消息中包含了事件相关的信息以及这个消息的处理人——Handler。每个进程中都有一个默认的消息队列(Message Queue,采用单链表的形式来存储消息列表),这个消息队列维护了一个待处理的消息列表,消息循环不断地从这个队列中取出消息、处理消息,这样使得应用动态地运作起来。
Message、MessageQueue、Looper、Handler的工作原理像是工厂的生产线,Looper是发动机,MessageQueue是传送带,Handler是工人,Message是待处理的产品。
消息通过Handler投递到消息队列,这个消息队列在Handler关联的Looper中,消息循环启动之后会不断地从队列中获取消息,其中消息的处理分为Native层和Java层,两个层次有自己的消息机制,Native层基于管道和epoll,而Java层则是一个普通的链表。获取消息后会调用消息的callback或者分发给对应Handler的handleMessage()处理。消息被处理之后会会受到消息池便于下次利用。
Handler 创建的适合会采用当前线程的 Looper 来构造消息系统。Handler 内部使用 ThreadLocal 获取当前线程的 Looper。ThreadLocal 可以在不同的线程中互不干扰的存储并提供数据。线程是默认没有 Looper 的,如果使用 Handler 就必须为线程创建 Looper。
Handler 的主要功能是将一个任务切换到某个指定的线程中去执行。这是因为 Android 规定访问 UI 只能在创建它的线程(大多数情况下 UI 都是从UI 线程中创建的),否则会抛出异常。(ViewRootImpl的checkThread()对UI操作做了验证:对UI控件的操作线程是否是创建它的线程)
系统为什么不允许在子线程中访问UI?
因为 android 的 UI 控件不是线程安全的,如果在多线程中并发访问可能会导致 UI 控件处于不可预期的状态。
为什么不对UI控件的访问加上锁机制? 缺点:
- 让UI访问的逻辑变复杂
- 降低UI访问的效率,会阻塞某些线程的执行
因此,单线程去处理UI控件的访问是最简单高效的。
使用 Handler:为当前线程创建 Looper 或者在有 Looper 的线程上。
- post(Runnable r) 将runnable包装到Message中
- sendMessage() (post最终也是调用send)
send() 被调用时,会调用MessageQueue的enqueueMessage将消息放到消息队列中。Looper 发现有新消息就会处理。最终 Runnable 或者 Handler 的 handleMessage() 就会被调用。
ThreadLocal
ThreadLocal ,也叫线程本地变量。是一个线程内部的数据存储类,可以在指定的线程中存储、获取数据。
应用场景:
- 以线程为作用域并且不同线程具有不同的数据副本。
- Looper的作用域是线程,不同线程有不同的Looper。
- 若不采用ThreadLocal,就要采用一个全局的HashMap实现LooperManager类
- Looper的作用域是线程,不同线程有不同的Looper。
- 复杂逻辑下的对象传递。比如监听器的传递。
- 监听器能贯穿整个线程的执行过程,在线程内部通过get()就能获得监听器。
- 若不采用ThreadLocal,
- 将监听器通过参数的形式在函数调用栈中进行传递。(函数调用栈太深 ×)
- 将监听器作为静态变量供线程访问。(10个线程就有10个静态变量。采用 ThreadLocal ,每个监听器对象都在自己的线程内部存储)
- 若不采用ThreadLocal,
- 监听器能贯穿整个线程的执行过程,在线程内部通过get()就能获得监听器。
class ThreadLocalTest {
private ThreadLocal<Boolean> booleanThreadLocal = new ThreadLocal<>();public static void main(String[] args) {
new ThreadLocalTest().test();}private void test(){
booleanThreadLocal.set(true);System.out.println("main---"+booleanThreadLocal.get());new Thread("thread1--"){
@Overridepublic void run() {
booleanThreadLocal.set(false);System.out.println("thread1--"+booleanThreadLocal.get());}}.start();new Thread("thread2--"){
@Overridepublic void run() {
System.out.println("thread2--"+booleanThreadLocal.get());}}.start();}
}
//main---true
//thread1--false
//thread2--null
ThreadLocal实例实际上也是被其创建的类持有(更顶端应该是被线程持有)。而ThreadLocal的值其实也是被线程实例持有。
它们都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。
public void set(T value) {
Thread t = Thread.currentThread();//1.首先获取当前线程对象ThreadLocalMap map = getMap(t);//2.获取该线程对象的ThreadLocalMapif (map != null)map.set(this, value);//如果map不为空,执行set操作,以当前threadLocal对象为key,实际存储对象为value进行set操作elsecreateMap(t, value);//如果map为空,则为该线程创建ThreadLocalMap
}
//Thread中的成员变量ThreadLocal.ThreadLocalMap threadLocals = null; //每个Thread线程中都封装了一个ThreadLocalMap对象//ThreadLocal类中获取Thread类中的ThreadLocalMap对象ThreadLocalMap getMap(Thread t) {
return t.threadLocals;}//ThreadLocal类中创建Thread类中的ThreadLocalMap成员对象void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);}
每一个Thread对象都有一个ThreadLocalMap对象,这样设计有两个目的:
- 可以保证当前线程结束时,相关对象可以立即被回收;
- ThreadLocalMap元素会大大减少,因为Map过大容易造成哈希冲突而导致性能降低。
public T get() {
Thread t = Thread.currentThread();//1.首先获取当前线程ThreadLocalMap map = getMap(t);//2.获取线程的map对象if (map != null) {
//3.如果map不为空,以threadlocal实例为key获取到对应Entry,然后从Entry中取出对象即可。ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();//如果map为空,也就是第一次没有调用set直接get(或者调用过set,又调用了remove)时,为其设定初始值
}
这样,实际上每个线程中都保存一份数据,Looper
就是这样保存在自身当前的线程中的。这也是为什么Looper
中的sThreadLocal
是static
的,却能在不同的线程中获取到自己线程的Looper
的原因。
2 MessageQueue 的工作原理
MessageQueue 只是一个消息的存储单元,不能处理消息。Looper 会以无限循环的形式去查询是否有新消息,有则处理,没有则等待。
其通过一个单链表来维护消息列表,单链表在插入和删除时有优势。
MessageQueue 主要包含两个操作:
- enqueueMessage():往消息队列插入一条消息(单链表的插入)
- next():从消息队列取出一条消息并移除
- 无限循环。如果消息队列没有消息就会一直阻塞在这里。当有新消息到来时,next()会返回这条消息并将它从单链表中移除。
3 Looper 的工作原理
3.1 Looper 的使用
Handler 的工作需要Looper,没有会报错。
Looper.prepare():为当前线程创建一个Looper
接着通过 Looper.loop() 来开启消息循环。
new Thread(){
@Overridepublic void run() {
Looper.prepare();Handler h = new Handler();Looper.loop();}
}.start();
prepareMainLooper()给ActivityThread创建Looper使用。
Looper.myLooper() 获取当前线程绑定的Looper,如果没有返回 null 。
Looper.getMainLooper() 返回主线程的 Looper ,这样就可以方便的与主线程通信。
Looper退出:
Looper.myLooper().quit();//直接退出Looper
Looper.myLooper().quitSafely();//设定一个退出标记,把消息队列中已有的消息全部处理完毕后再安全退出
Looper退出后,通过Handler发送的消息会发送失败,Handler的send()会返回false。
在子线程中,若手动创建了Looper,当所有事情完成后应退出Looper来终止消息循环,不然子线程会一直处于等待状态。退出Looper后,这个线程会立刻终止,建议在不需要的时候调用上述两个方法退出Looper。
3.2 Looper 底层原理
//Looper的作用域是线程,不同线程有不同的Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建一个消息队列mThread = Thread.currentThread();//将当前线程的对象保存
}public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
Looper.prepare():为当前线程创建一个Looper
public static void prepare() {
prepare(true);
}private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));
}
Looper.loop() 来开启消息循环。
public static void loop() {
final Looper me = myLooper();if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"+ " before this one completed.");}me.mInLoop = true;final MessageQueue queue = me.mQueue;//...for (;;) {
//死循环Message msg = queue.next(); // might blockif (msg == null) {
//当msg为空才跳出循环return;}//...}
}
loop()是一个死循环,唯一跳出循环的方式是 MessageQueue 的 next() 返回 null 。(当调用Looper的quit() 时会标记一个退出状态,MessageQueue的next也就会返回null)
MessageQueue 的 next() 也是一个死循环,当没有新消息时会阻塞在那里。所以 Looper 的 loop() 也会阻塞,因此死循环会一直持续。在完毕后必须退出Looper才能终止消息循环。
当MessageQueue的next返回了新消息,Looper会处理这个消息:msg.target.dispatchMessage(msg) (这里msg.target是发送这条消息的Handler对象),这样消息就又交给它的dispatchMessage()来处理(在Handler所在的线程处理),最终返回到 Handler 的 handleMessage(Message msg)处理。
4 Handler的工作原理
Handler 是 Android 消息机制的上层接口,在开发过程中只需和 Handler 交互即可。
4.1 Handler简单应用
UI 不可以在不是它创建的线程里更新 -> 即 UI 不可以在子线程更新。
- post()
public class MainActivity extends Activity{
Handler mHandler = new Handler(Looper.getMainLooper());private void dosomething(){
new Thread(){
@Overridepublic void run(){
//耗时操作,得到结果//通过 Handler 将结果传到主线程,并更新UImHandler.post(new Runnable(){
@Overridepublic void run(){
//更新UI}});}}.start();}
}
- sendMessage()
public class MainActivity extends Activity{
Handler mHandler = new Handler(Looper.getMainLooper()){
@Overridepublic void handleMessage(Message msg) {
switch (msg.what){
//根据msg.what处理信息case 1:System.out.println("handleMessage thread id " + Thread.currentThread().getId());System.out.println("msg.arg1:" + msg.arg1);System.out.println("msg.arg2:" + msg.arg2);break; }} };private void dosomething(){
new Thread(){
@Overridepublic void run(){
//耗时操作,得到结果 Message msg = new Message();msg.what = 1;//出不同的Message,以便我们做出不同的处理操作msg.arg1 = 123;//可以通过arg1和arg2给Message传入简单的数据msg.arg2 = 321;//通过 Handler 将结果传到主线程,并更新UIHandler.sendMessage(msg);}}.start();}
}
4.2 Handler 原理
就上面的例子来说,通过 Handler 传递了一个 Runnable 给UI线程。实际上 Runnable 会被包装到一个 Message 对象中,然后再投递到UI线程的消息队列。
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r),0);//再将这个对象传给 sendMessageDelayed()
}private static Message getPostMessage(Runnable r){
Message m = Message.obtain();//obtain()会从被回收的对象池中获取Message对象(回收指将Message对象不使用时会被回收到消息池中)没有则新建m.callback = r;//将Runnable包装到一个 Message 对象中return m;
}
sendMessageDelayed() 最终又调用了 sendMessageAtTime() :
- 获取当前 Handler 所在的消息队列(Handler 从持有的Looper中获取消息队列)
- 判断消息队列是否为空,不为空则将该消息追加到消息队列中。为空则报异常。
Handler发送消息的过程仅仅是像消息队列中插入了一条消息。MessageQueue 的 next() 就会返回一个新消息给 Looper,Looper收到新消息就开始处理(交给Handler处理),最终调用 Handler 的 dispatchMessage(Message msg)
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
//使用的post:Runnable即为mCallback。handleMessage调用了Runnable的run()return;}}handleMessage(msg);//否则调用的是sendMessage().}}
5 主线程的消息循环
主线程即UI线程,就是 ActivityThread , ActivityThread被创建时就会初始化Looper,这也是主线程默认可以使用 Handler 的原因。
Android应用程序的入口实际上是 ActivityThread.main() :首先会创建 Application 和默认启动的Activity,并将它们关联在一起。该应用的UI线程的消息循环也是在这里创建的。
public ststic void main(String[] args){
//...Process.setArgV0("pre-initialized");//1.创建消息循环Looper,就是UI线程的消息队列Looper.prepareMainLooper();//启动ActivityThread,这里最终会启动应用程序ActivityThread thread = new ActivityThread();thread.attach(false);AsyncTask.init();//2.执行消息循环Looper.loop();
}
此后Looper会一直从消息队列中取消息,然后处理消息。用户或系统通过Handler不断往消息队列中添加消息,这些消息不断地被取出、处理、回收,使得应用迅速地运转起来。
主线程的消息循环开始后,ActivityThread 还需要一个 Handler 来和消息队列进行交互,这个就是 ActivityThread.H ,它内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程。
private class H extends Handler {
//启动Activity
public static final int LAUNCH_ACTIVITY = 100;
//暂停Activity
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
//...
}
ActivityThread 通过 ApplicationThread 和 AMS 进行进程间的通信,AMS以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 中的Binder方法,然后 ApplicationThread 会向 H 发送消息,H收到消息后切换到主线程(ActivityThread)中去执行。这个过程就是主线程的消息循环模型。
6 AsyncTask
6.1 线程和线程池
线程主要分为主线程(UI线程)和子线程(工作线程),主线程主要处理和界面相关的事情,子线程主要处理一些耗时操作。
除了 Thread 以外,在 Android 中扮演线程角色:AsyncTask、IntentService,HandleThread也是一种特殊的线程。
- AsyncTask的底层用了线程池
- 封装了线程池和Handler
- 作用:为了方便开发者在子线程更新UI
- IntentService,HandleThread的底层直接用了线程
- IntentService:是一种服务。内部采用HandleThread来执行任务,任务结束后退出。
- HandleThread:是一种具有消息循环的线程。其内部实现为:Handle + Thread + Loop
6.2 AsyncTask 的使用
AsyncTask是一种轻量级的异步任务类,可以在线程池中执行后台任务,把执行进度和最终结果传到主线程并更新UI。(被api30弃用,直接使用线程池+Handler或者使用Kotlin的协程)
注意:只适合不太耗时的后台任务,对于特别耗时的任务还是交给线程池去处理。
AsyncTask本质上就是Handler+Thread封装。
public abstract class AsyncTask<Params, Progress, Result>//三个泛型参数
//Params:参数类型
//Progress:执行进度的类型,一般情况为Integer
//Result:返回结果的类型
4个核心方法:
protected void onPreExecute() {
}
protected abstract Result doInBackground(Params... params);
protected void onProgressUpdate(Progress... values) {
}
protected void onPostExecute(Result result) {
}
- onPreExecute():在主线程执行,在异步任务执行前执行,做一些准备工作。
- doInBackground(Params… params):在线程池执行,用于执行异步任务。
- onProgressUpdate(Progress… values):在主线程中执行,当后台任务的执行进度发生改变时会调用此方法。
- onPostExecute(Result result):在主线程执行,异步任务完成后调用。
使用:
class DownloadFilesTask extends AsyncTask<URL,Integer,Long> {
@Overrideprotected Long doInBackground(URL... urls) {
int cnt = urls.length;long totalSize = 0;for(int i=0;i<cnt;i++){
totalSize += DownLoader.downloadFile(urls[i]);//进度发生变化调用publishProgress(Process process)publishProgress((int) ((i/(float)cnt)*100));if(isCancelled()){
break;}}return totalSize;}@Overrideprotected void onProgressUpdate(Integer... process) {
setProgressPercent(process[0]);}@Overrideprotected void onPostExecute(Long result) {
showDialog("Download"+result+" bytes");}
}
在主线程调用
new DownloadFilesTask.execute(url1,url2,url3);
6.3 AsyncTask 工作原理
AsyncTask最适合使用的场景是多线程,开始在代码中已经看到了在AsyncTask内部有自己维护的线程池,默认的是SERIAL_EXECUTOR
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
为什么要求AsyncTask在主线程加载(AsyncTask用于更新UI时)?
在执行AsyncTask构造方法时,会初始化内部handler,会判断
- 传入的Looper为空或者传入的Looper是主线程的Looper:获取静态Handler(处于主线程的Handler)
- 否则:创建一个传入Looper的子线程的Handler
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() //要求AsyncTask在主线程加载? getMainHandler(): new Handler(callbackLooper);}//mHandler初始化private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());}return sHandler;}}//sHandlerprivate static InternalHandler sHandler;private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);}@SuppressWarnings({
"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {
case MESSAGE_POST_RESULT://收到任务结束:调用finish() 返回结果result.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS://收到更新进度:调用onProgressUpdate() 更新进度result.mTask.onProgressUpdate(result.mData);break;}}}
InternalHandler用于将执行环境从线程池切换到主线程。
//构造方法
public AsyncTask() {
this((Looper) null);
}public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() //要求AsyncTask在主线程加载? getMainHandler(): new Handler(callbackLooper);mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);Result result = null;try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams);//执行耗时操作Binder.flushPendingCommands();} catch (Throwable tr) {
mCancelled.set(true);throw tr;} finally {
postResult(result);//结果传给内部的Handler(跳转主线程返回结果)}return result;}};mFuture = new FutureTask<Result>(mWorker) {
@Overrideprotected void done() {
try {
postResultIfNotInvoked(get());} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",e.getCause());} catch (CancellationException e) {
postResultIfNotInvoked(null);}}};
}//postResult:结果传给内部的Handler(跳转主线程返回结果)private Result postResult(Result result) {
// getHandler()返回的是InternalHandler实例,一个主线程HandlerMessage message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();//Handler发送消息return result;}//obtainMessage((what)MESSAGE_POST_RESULT,(Object)new AsyncTaskResult<Result>(this, result))public final Message obtainMessage(int what, @Nullable Object obj) {
return Message.obtain(this, what, obj);}//AsyncTaskResultprivate static class AsyncTaskResult<Data> {
final AsyncTask mTask;final Data[] mData;AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;mData = data;}}
初始化两个对象:mWorker、mFuture。mWorker是一个Callable对象,作为mFuture的构建参数。mFuture是一个FutureTask对象,并在初始化mFuture的时候将mWorker作为参数传入。
public class FutureTask<V> implements RunnableFuture<V> {
//...public FutureTask(Callable<V> callable) {
if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable}public void run() {
if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return;try {
Callable<V> c = callable;if (c != null && state == NEW) {
V result;boolean ran;try {
//然后调用线程池的execute()方法(执行mFuture的run方法)。//执行具体的耗时任务,即开头构造函数中mWorker中call()方法的内容。//先执行完doInBackground()方法,又执行postResult()方法result = c.call();ran = true;} catch (Throwable ex) {
result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {
runner = null;int s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}//...
}
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);//把mFuture加载到串行线程池return this;}
exec也就是sDefaultExecutor 是一个串行的线程池,一个进程中的所有的 AsyncTask 全部在这个串行的线程池中排队执行。具体是SerialExecutor类
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor SERIAL_EXECUTOR = new SerialExecutor();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();//1.加入新任务,即mFuture} finally {
scheduleNext();//调用THREAD_POOL_EXECUTOR执行队列头部的任务}}});//判断是否有正在执行的任务,没有的话,就执行下一个任务if (mActive == null) {
scheduleNext();}}protected synchronized void scheduleNext() {
// 从任务队列里获取一个任务,并放到线程池中去执行if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);}}}
SerialExecutor 内部维持了一个队列,通过锁使得该队列保证AsyncTask中的任务是串行执行的,即多个任务需要一个个加到该队列中,然后执行完队列头部的再执行下一个,以此类推。
AsyncTask维护了两个线程池(SerialExecutor、THREAD_POOL_EXECUTOR):
- SerialExecutor:用于任务的排队
- THREAD_POOL_EXECUTOR:用于真正执行任务
THREAD_POOL_EXECUTOR:实际是个线程池,开启了一定数量的核心线程和工作线程。
public static final Executor THREAD_POOL_EXECUTOR;static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), sThreadFactory);threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);THREAD_POOL_EXECUTOR = threadPoolExecutor;}
然后调用线程池的execute()方法。执行具体的耗时任务,即开头构造函数中mWorker中call()方法的内容。先执行完doInBackground()方法,又执行postResult()方法,下面看该方法的具体内容:
//postResult:结果传给内部的Handler(跳转主线程返回结果)
private Result postResult(Result result) {
// getHandler()返回的是InternalHandler实例,一个主线程HandlerMessage message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}
该方法向Handler对象发送了一个消息,下面具体看AsyncTask中实例化的Hanlder对象的源码:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());}@SuppressWarnings({
"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {
case MESSAGE_POST_RESULT:// 调用finish()result.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS://更新进度result.mTask.onProgressUpdate(result.mData);break;}}}
在InternalHandler 中,如果收到的消息是MESSAGE_POST_RESULT,即执行完了doInBackground()方法并传递结果,那么就调用finish()方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);} else {
onPostExecute(result);}mStatus = Status.FINISHED;}
如果任务已经取消了,回调onCancelled()方法,否则回调 onPostExecute()方法。
AsyncTask的默认线程池(SerialExecutor)是串行的。若想使用并行执行任务,可使用executeOnExecutor()传入自定义的线程池来执行任务。
在executeOnExecutor中可以传入自己自定义的线程池:
//跟默认一样的按顺序执行
asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor());
//无限制的Executor
asyncTask.executeOnExecutor(Executors.newCachedThreadPool());
//同时执行数目为10的Executor
asyncTask.executeOnExecutor(Executors.newFixedThreadPool(10));
AsyncTask 其他属性:
//获取CPU数目
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心工作线程(同时执行的线程数)
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//线程池允许的最大线程数目
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空闲线程超时时间(单位为S)
private static final int KEEP_ALIVE = 1;
//线程工厂
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());}
};
//阻塞队列,用来保存待执行的任务(最高128个)
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
6.4 AsyncTask 使用不当的后果
- 生命周期
AsyncTask不与任何组件绑定生命周期,所以在Activity/Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);
- 内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
- 结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。