Android多线程之 HandlerThread 源码分析
文章目录
一、前言
这主要是一个讲解 Android
中多线程的系列,全部文章如下:
- Android 多线程之 Handler 基本使用
- Android 多线程之 Handler 源码分析
- Android 多线程之 HandlerThread源码分析
- Android 多线程之 AsyncTask使用源码分析
- Android 多线程之 IntentService使用源码分析
前面写了 Android
中的消息机制,也就是 Handler
的消息机制。不了解的可以去看下 Handler系列—源码分析。
本章就来使用和分析下 HandlerThread
。
二、什么是 HandlerThread?
我们看下官方的描述:
可以看到 HandlerThread
是继承于 Thread
类的,说明我们可以使用它开启一个子进程去执行一些操作。
再看下官方说明:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
这个类可以方便的开启一个带有
Looper
的新线程。这个looper
可以去创建一个Handler
,但是还是必须得调用start()
方法。
我们大概知道 HandlerThread
更加方便了我们在 Android
中进行多线程消息传递。
下面我们通过实例了解下:
public class HandlerThreadTestActivity extends AppCompatActivity {
private static final String TAG = "HandlerThreadTest";
private TextView mShow;
private HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread_test);
mShow = findViewById(R.id.show);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message message) {
super.handleMessage(message);
final int what = message.what;
mShow.setText("得到的 what 为: "+what );
Log.d(TAG, "handleMessage: " + message.what);
}
};
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(1));
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(2));
}
});
findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
});
}
}
运行程序,不出意外会得到如下异常:
原因已经很清楚了,我们在子线程中做了更新 UI 的操作。
下面来分析下原因:
由于 HandlerThread
是继承于 Thread
的,所以在实例化的 HandlerThread
对象是一个子线程,我们在创建 Handler
的时候,传入了 mHandlerThread
对象所在的线程的 Looper
对象,一个线程中只能有一个 Looper
对象,进而使 mHandler
和 子线程进行了绑定,所以这个 mHandler
是属于 mHandlerThread
的。
大家都知道只有主线程的 Handler
对象才能够进行更新 UI
的操作,所以在 mHandler
中执行 UI
操作时肯定不行的。
所以我们需要这样写:
runOnUiThread(new Runnable() {
@Override
public void run() {
mShow.setText("得到的 what 为: "+what );
}
});
代码 才能真正的运行。
通过上面的分析,大家应该能够知道 HandlerThread
是什么了。
- 由于继承于
Thread
,所以HandlerThread
就是一个线程类; HandlerThread
内部拥有一个Looper
循环,可以直接传递给Handler
使用
其实 HandlerThread
就是一个包含了 Looper
的 Thread
,可以免去我们在子线程中创建 Handler
的时候写一些多余的代码。
比如我们在上篇文章的 2-1 章节 章节中创建一个子线程中的 Handler :
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler threadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}).start();
使用了 HandlerThread 以后我们只需要:
private HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
Handler threadHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
这样看上去是不是清晰了许多?就是省去了创建 Looper
和 开启 loop
的操作
三、HandlerThread 解析
由于这个类的代码很少,我们都看下。
1.成员变量和构造方法
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
}
可以看到,HandlerThread
的成员变量很简单,
mPriority
是优先级mTid
是线程的标示符,主要和线程的优先级有关mLooper
是内部持有的Looper
对象mHandler
是与之绑定的Handler
对象
构造方法也只有两个:
-
第一个构造函数
第一个只需要传入线程的名称就行了,会把线程的优先级设置了默认的 -
第一个构造函数
第二个则根据自己的需要传入线程的名称和优先级,根据注释可以知道,这个优先级必须是从android.os.Process
类中获取,不能从Thread
类中获取
2、onLooperPrepared 方法
继续往下看,会看到一个空实现的方法
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
根据注释可以知道,这个方法是给我们在创建 Looper 之后,开启 Looper 循环之前的一些操作使用的。
也就是说在 Looper.prepare()
之后 ,在 Looper.loop()
之前需要做的操作,写在这里,上一篇 Handler
源码解析的文章有写到,这里就不多说了。
3、核心 run
方法
由于继承于 Thread
,要重写 Thread
的核心方法 run()
方法。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
这里首先会调用 Looper.prepare()
创建一个新的 Looper
对象,关于里面的内容,如果看过上篇文章,应该就知道了。
创建完 Looper
以后,通过 Looper 的 Looper.myLooper()
赋值给其成员变量 mLooper
。
Process.setThreadPriority(mPriority);
就是设置线程的优先级,
onLooperPrepared();
就是上面的空方法
Looper.loop();
开启 Looper
循环,不断的查看 MessageQueue
中有没有新消息
最终执行完以后把 mTid置为 -1。
可能你发现了 notifyAll();
这个方法,那么是干嘛的呢?其实我在 Java多线程 有讲到:
Object
类中提供了 wait()
方法,导致当前线程等待,直到其他线程调用此对象的 notify()
方法或 notifyAll()
唤醒方法,才会继续执行。
其实这个地方的 notifyAll()
和下面的 getLooper()
代码是有关的。
4. 获取 Looper
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
.
然后我们就看到了的上面提到的 wait()
方法,也就是说如果这个线程没有执行 run()
方法之前,就去调用 getLooper()
是拿不到的。只有执行了 run()
方法了以后,执行了 notifyAll
才会继续解除这里的 wait
等待,才能正确的获取到 mLooper
对象。
5. 其他方法
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
getThreadHandler
获取一个和当前线程关联的 Handler 对象
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
quit
退出 Handler
线程的循环
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
quitSafely
安全的退出 Handler
线程的循环
上面的 quit
和 quitSafely
都调用了 MessageQueue
中的方法:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
-
quit
调用了removeAllMessagesLocked()
;作用是把
MessageQueue
消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed
或通过postDelayed
等方法发送的需要延迟执行的消息)还是非延迟消息。 -
quitSafely
调用了removeAllFutureMessagesLocked()
该方法只会清空
MessageQueue
消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler
去处理,quitSafely
相比于quit
方法安全之处在于清空消息之前会派发所有的非延迟消息。
无论调用了 quit
还是 quitSafely
,线程中的 Looper
都不会接受新的消息了,消息队列终结,这时候再通过 Handler
调用 sendMessage
或 post
等方法发送消息时均返回 false
,表示消息没有成功放入消息队列 MessageQueue
中,因为消息队列已经退出了。
四、小结
至此 HandlerThread
的源码已经分析完了,相对来说 HandlerThread
就是做了一些封装,理解和用起来都是不难的。
下篇文章看下 AsyncTask
。