前面分析完了Handler源码,但是还有很多不为人知的秘密,接下来分析它。
涉及到的类:
HandlerThread、IntentService、AsyncTask、Messenger、IdleHandler、Looper.Observer、MessageLogging等
上半部分讲解内容:HandlerThread、IntentService、AsyncTask
下半部分讲解内容:Messenger、IdleHandler、Looper.Observer、MessageLogging
1. HandlerThread
背景:在Android系统中使用消息机制进行线程间的消息传递。如果要在子线程中传递消息,就需要创建一个子线程的Handler。
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler workHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// 处理子线程的消息
return false;
}
});
// 发送消息
workHandler.sendEmptyMessage(0);
Looper.loop();
}
}).start();
这种方式虽然可以实现在子线程中进行消息的传递,但很麻烦且该子线程不能退出循环。Android为我们提供了很好的组件HandlerThread。
查看源码发现,HandlerThread是继承Thread,在内部维护一个Looper,当线程开启后run方法运行起来,就会创建一个Looper。定义如下:
/**
* A {@link Thread} that has a {@link Looper}.
* The {@link Looper} can then be used to create {@link Handler}s.
* <p>
* Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
*/
public class HandlerThread extends Thread {}
它的主要作用:处理单线程的耗时任务。
1.1 基本使用
创建HandlerThread(需要指定线程的名字)后,必须先启动HandlerThread线程。
HandlerThread handlerThread = new HandlerThread("AsyncThreadTask");
handlerThread.start(); // 启动线程
// 创建Handler时需要指定HanderThread中创建的Looper对象
Handler workHandler = new Handler(handlerThread.getLooper());
// 发送消息
workHandler.post(new Runnable() {
@Override
public void run() {
// 处理耗时任务
}
});
// 退出消息循环,发送的消息就不会被处理了
handlerThread.quit();
1.2 源码解析
HandlerThread的源码很简单只有100多行,先来看下它的构造方法
// HandlerThreadde.java源码
int mPriority; // 线程优先级
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
构造方法参数有两个:
- name 线程的名字
- priority 线程的优先级
线程start()后run方法执行,当前线程绑定Looper对象,并循环该线程中的消息。
// HandlerThreadde.java源码
Looper mLooper; // 当前线程持有的Looper对象
// Looper已经创建完成调用
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 创建Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); // 唤醒等待的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //
mTid = -1;
}
提供了获取当前线程的Looper的方法。
// HandlerThreadde.java源码
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
如果当前线程没有运行,直接返回null;如果当前线程已经运行,但Looper还没有创建完成,则wait,等待Looper创建完成,否则直接返回该线程的Looper对象。
2. IntentService
背景:在Android应用的程序中,如果Service中处理耗时的操作,很容易出现ANR的现象,通常的做法就是,在onStartCommon方法中开启一个子线程然后内部执行耗时的操作,在执行完毕后如果停止服务,还需要手动的在子线程的run方法中调用stopSelf()来停止服务。
其实IntentService,就是Service 和 HandlerThread 的结合体。
IntentService定义的三个基本点:是什么?怎么用?如何work?
/**
1、是什么?
IntentService is a base class for {@link Service}s that
handle asynchronous requests (expressed as {@link Intent}s) on demand.
2、怎么用?
Clients send requests through
{@link android.content.Context#startService(Intent)} calls;
3、如何work?
the service is started as needed, handles each Intent
in turn using a worker thread, and stops itself when it runs out of work.
*/
public abstract class IntentService extends Service {}
1、IntentService特点
- IntentService是Service类的子类,用来处理异步请求
- IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue单链表的形式
- 由于是单线程(一个工作线程),所以所有的任务需要排队执行
2、 IntentService的优点和缺点
IntentService相对与Service的好处:
- 使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
- 当操作完成时,我们不用手动停止Service
但是它的缺点也显而易见:
- 由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况
- 不适合用于bindService()这样的启动方式的
2.1 简单使用
1、IntentService是一个抽象类,内部有一个抽象方法onHandleIntent。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d(TAG, "onHandleIntent: " + Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
2、清单文件AndroidManifest中配置
// AndroidManifest.xml
<service android:name=".MyIntentService" />
3、调用startService(Intent)启动IntentService
Intent service = new Intent(this, MyIntentService.class);
startService(service);
2.2 源码简单分析
1、IntentService是Service的子类,拥有Service的所有生命周期方法,内部还有一个ServiceHandler
// IntentService.java源码
public abstract class IntentService extends Service {
// ServiceHandler继承Handler,创建时必须传入一个Looper
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);
}
}
public IntentService(String name) {
super();
mName = name;
}
protected abstract void onHandleIntent(@Nullable Intent intent);
}
2、onCreate()的源码,创建HandlerThread。
// IntentService.java源码
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
IntentService服务开启后就会创建Handler线程(HandlerThread),并获取当前线程的Looper对象,然后关联到Handler中。
3、接下来是onStart()源码,调用mServiceHandler
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
当你启动IntentService的时候,就会产生一条附带startId和Intent的 Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler 处理消息。
4、handleMessage处理消息的代码
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
接着调用 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,其实就是我们要重写实现的方法,我们可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作。
5、stopSelf(msg.arg1)
回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.如果传入的是-1则直接销毁。
6、onDestroy()
@Override
public void onDestroy() {
mServiceLooper.quit();
}
服务结束后调用这个方法 mServiceLooper.quit()使looper停下来。
2.3 问题记录
1、在源码handleMessage方法中为什么执行完handleIntent方法会去调用带参数的stopSelf()
因为stopSelf()的执行会立刻将服务停止掉(内部实现调用带参数的stopSelf,传入的值是-1),而带参数的stopSelf(int startId)会在所有任务执行完毕后将服务给停止。通常情况下调用stopSelf(int satrtId)方法不会立刻去执行停止服务的操作,会去判断最近执行任务的getLastStartId是否和startId相等,如果相等就立刻执行停止服务的操作。
3. AsyncTask
为了简化在子线程中访问UI的过程,系统提供了AsyncTask,但不同的API版本AsyncTask具有不同的表现。
AsyncTask是一种轻量级的异步任务类,可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程中更新UI。AsyncTask=Thread+Handler
AsyncTask是一个抽象的泛型类,它提供了Params,Progress,Result这三个泛型参数。
- Params 参数类型
- Progress 后台任务的执行进度类型
- Result 后台任务的返回结果类型
public abstract class AsyncTask<Params, Progress, Result> { }
AsyncTask提供了4个核心方法
1、 onPreExecute() 在主线程中执行,在异步任务执行之前,此方法会被调用,一般用于做一些准备工作
2、doInBackground(Params... params) 在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的输入参数。在此方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法。此方法需要返回计算结果给onPostExecute方法。
3、onProgressUpdate(Progress... values),在主线程中执行,当后台任务的执行进度发生改变时通过publishProgress方法更新后此方法会被调用。
4、onPostExecute(Result result) 在主线程中执行,在异步任务执行之后,此方法会被调用,其中result参数就是后台任务的返回值,即doInBackground的返回值
除了这个四个方法外,还提供了onCancelled()方法,也是在主线程中执行,当任务被取消时会被调用,但onPostExecute不会被调用。
AsyncTask的源码分析
1、为了分析AsyncTask的工作原理,从execute方法开始分析,execute方法又会调用executeOnExecutor方法
// AsyncTask.java源码
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
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;
}
sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。在executeOnExecutor方法中,AsyncTask的onPreExecute方法最先执行,然后线程池开始执行。
2、分析线程池的执行过程
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();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
// 从队列的头部获取一个任务,并赋值给mActive。当队列为空,mActive就为null
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
SerialExecutor的execute的方法把一个任务插入到任务队列mTasks中,如果此时mActive为null,表示没有正在活动的任务,就会调用SerialExecutor的scheduleNext方法来执行下一个任务,当执行完任务后,会从队列中获取下一个任务执行,如果任务队列中没有任务就执行完成。
3、AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),
- 线程池SerialExecutor用于任务的排队
- 线程池THREAD_POOL_EXECUTOR用于真正地执行任务
- InternalHandler用于从线程池切换到主线程执行
在AsyncTask的构造方法中,由于FutureTask的run会调用mWorker的call方法,所以mWorker的call方法最终在线程池中执行。
// AsyncTask的构造方法
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected 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);
}
}
};
在doInBackground执行完后,将返回结果传给postResult方法
private Result postResult(Result result) {
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
Handler收到MESSAGE_POST_RESULT这个消息后会调用AsyncTask的finish方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果消息被取消了,执行onCancelled方法,否则调用onPostExecute方法。
如果我的文章对您有帮助,不妨点个赞鼓励一下(^_^)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。