Handler系列文章:java
HandlerThread是什么?HandlerThread的官方定义是:用于启动具备looper的新线程的方便类。而后可使用looper来建立Handler类。bash
简而言之就是:HandlerThread是一个启动好Looper的Thread对象,方便将Handler绑定在该线程中。ide
//建立子线程Handler
HandlerThread mHandlerThread = new HandlerThread("daqi");
mHandlerThread.start();
Handler mHandler = new Handler(mHandlerThread.getLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
}
});
复制代码
HandlerThread实际继承自Thread,实际也是一个Thread对象。oop
其中存在3个比较重要的变量:
一、mPriority 线程优先级
二、mLooper 本线程的Looper
三、mHandler 自带的Handler变量
源码分析
#HandlerThread.java
public class HandlerThread extends Thread {
int mTid = -1;
//线程优先级
int mPriority;
//HandlerThread的Looper对象
Looper mLooper;
//自带的Handler
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
//使用默认优先级
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
}
复制代码
当不指定线程优先级建立HandlerThread时,使用默认优先级初始化线程。post
Thread对象最关键的就是run(),先从run方法看起:ui
HandlerThread.java
@Override
public void run() {
mTid = Process.myTid();
//初始化Looper对象
Looper.prepare();
//加锁
synchronized (this) {
//获取该Thread的Looper对象
mLooper = Looper.myLooper();
//getLooper()再解析
notifyAll();
}
//设置该线程的优先级
Process.setThreadPriority(mPriority);
//Looper初始化完毕回调方法,用户可在这里初始化Handler
onLooperPrepared();
//启动Looper循环器
Looper.loop();
mTid = -1;
}
复制代码
先初始化本线程的Looper对象,并赋值到mLooper对象上。
this
再回调onLooperPrepared(),用户可重写该方法,在该方法中进行初始化Handler的操做。
spa
最后才调用Looper#loop()启动Looper的循环获取Message机制。
线程
总得来讲HandlerThread#run()中进行了Looper初始化和Looper初始化完毕回调。
常用HandlerThread#getLooper()在初始化Handler时指定Handler所在的线程。查看getLooper()源码:
public Looper getLooper() {
//isAlive()检测线程是否还存活
if (!isAlive()) {
return null;
}
//加锁
synchronized (this) {
//当mLooper不为空时,才会返回mLooper
while (isAlive() && mLooper == null) {
try {
//等待
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
复制代码
当Looper没被初始化完毕时,调用getLooper()的线程会被挂起,等待Looper初始化完毕调用notifyAll()将其唤醒。
当HandlerThread再也不使用时,须要调用quit()或quitSafely()退出Looper的循环机制。
由于run方法最后调用Looper#loop(),启动循环获取Message机制,run方法被"卡"在Looper#loop()上。只要当Looper退出循环机制时,run方法才执行完毕,线程也就“完成任务”自我销毁。
那 quit() 或 quitSafely() 有什么区别呢?
#HandlerThread.java
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
复制代码
#Looper.java
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
复制代码
区别就是调用MessageQueue#quit()方法时,传递的boolean值参数不同。继续查看MessageQueue#quit()的源码:
#MessageQueue.java
void quit(boolean safe) {
//...
synchronized (this) {
if (mQuitting) {
return;
}
//标记正在退出
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
复制代码
当调用HandlerThread#quitSafely()时,最终调用MessageQueue#removeAllFutureMessagesLocked()
当调用HandlerThread#quit()时,最终调用MessageQueue#removeAllMessagesLocked()
private void removeAllMessagesLocked() {
//获取链表表头
Message p = mMessages;
//直接将Message链表所有回收
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
//将链表头置空
mMessages = null;
}
private void removeAllFutureMessagesLocked() {
//获取当前手机开机时间
final long now = SystemClock.uptimeMillis();
//获取MessageQueue中的Message链表表头
Message p = mMessages;
if (p != null) {
//若是链表表头Message对象的‘执行时间’比如今小,即代表当前暂无须要执行的Message
if (p.when > now) {
//即走quit()的路线,所有清除链表中的Message
removeAllMessagesLocked();
} else {
//不然当前存在须要立刻执行 但又未发送到目标Handler进行处理的Message。
Message n;
for (;;) {
n = p.next;
//找到链尾尚未找到比当前时间大,即表示当前Message链表中的所有Message都是在退出前发送的,或者说在退出以前须要执行,但如今还没执行的。
//同时也表示没有延迟执行的Message,无须要清理的Message,直接退出方法。
if (n == null) {
return;
}
//当找到第一个不是立刻执行的Message对象时,退出死循环。
if (n.when > now) {
break;
}
p = n;
}
//此时for循环退出,说明找到比当前开机时间大,须要延迟执行的Message。
//p.when仍比now(即当前开机时间)小,p.next.when才是比now大的。
//将p.next置空,即p做为当前链表的链尾,后面延迟的Message再也不在链表中。
p.next = null;
//死循环,直到到链尾
//不断回收when比当前开机时间大的Message。
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
复制代码
从这两个源码中看出:
HandlerThread#quit()会所有清空MessageQueue中Message链表。
HandlerThread#quitSafely()先获取当前手机开机时间 now,只清除when大于now的Message,即被延迟处理的Message。
而对于小于当前手机开机时间的Message,则进行保留。而那些Message本该在HandlerThread退出前被处理的,但被正在处理的Message“卡住”,还没来得及处理,被迫留在Message链表中。
HandlerThread中还有一个不多被使用的方法,返回一个绑定当前线程的Handler实例:
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
复制代码
为何HandlerThread要和IntentService一块儿讲?由于IntentService其内部使用的就是HandlerThread,一个活生生的HandlerThread”实战案例“。加之有刚才HandlerThread的源码基础,理解IntentService源码也事半功倍。
什么是IntentService?简单点说就是:自带工做线程的Service。
IntentService是抽象类,须要继承实现onHandleIntent()方法。在方法中处理启动Service时传递的Intent对象。 IntentService也是Service的子类,听从Service的生命周期。先从onCreate()方法看起:
#IntentService.java
public abstract class IntentService extends Service {
//工做线程Looper
private volatile Looper mServiceLooper;
//绑定工做线程的Handler
private volatile ServiceHandler mServiceHandler;
//HandlerThread的名称
private String mName;
//
private boolean mRedelivery;
//定义一个内部Handler类
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//将Message中存储的Intent对象,回调onHandleIntent(),传递给用户处理。
onHandleIntent((Intent)msg.obj);
//尝试自我销毁
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
//建立HandelrThread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//存储工做线程的Looper
mServiceLooper = thread.getLooper();
//建立handler并将其绑定在工做线程中。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
}
复制代码
初始化IntentService时,会建立IntentService工做的子线程,将初始化其内部Handler,绑定在工做线程中。
#IntentService.java
@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;
}
复制代码
启动service时,只有第一次初始化时才会调用onCreate(),onStartCommand()和onStart()每次都被调用。onStartCommand会告诉系统如何重启服务,如判断是否异常终止后从新启动等。
onStartCommand()中会调用onStart()。IntentService#onStart(Intent,int)中将Intent对象封装成Message对象,交由Handler进行发送。
而内部的Handler对象在handleMessage()中,将Intent对象从Message中取出,回调onHandleIntent(),交由用户进行处理。
最后onStartCommand的返回存在两种状况:
一、START_REDELIVER_INTENT:若是此Service的进程在启动时被终止(即返回onStartCommand(Intent,int,int)以后),则Service将会被安排从新启动,而且最后一次传递的Intent将再次经过onStartCommand(Intent,int,int)从新传递给Service。
二、START_NOT_STICKY:若是在执行完onStartCommand后,服务被异常终止,系统不会自动重启该服务。
mRedelivery用来标识是否将最后一次的Intent从新传递一遍。能够经过setIntentRedelivery进行设置:
#IntentService.java
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
复制代码
通常状况下,mRedelivery为默认值,即为false。因此onStartCommand()通常返回START_NOT_STICKY,即被杀死后,则不从新启动再传递一次最后的Intent对象。
@Override
public void onDestroy() {
mServiceLooper.quit();
}
复制代码
IntentService被销毁时,也会退出Looper,结束工做线程。