有时候我们需要在应用程序中创建一些
常驻的子线程不定期地执行一些计算型任务
,这时候可以考虑使用HandlerThread,它具有
创建带消息循环的子线程
的作用。
可通过构造器注入线程优先级,默认优先级为Process.THREAD_PRIORITY_DEFAULT
核心逻辑为run方法(复写Thread类的run方法):
外界可通过getLooper方法获取Looper对象:
然后通过Looper.myLooper方法返回与本线程绑定的Looper,正是刚创建的Looper:
Looper.loop方法将启动消息循环,不断从其内部封装的消息队列MessageQueue中取出消息,交由Handler执行。
一、HanderThread使用示例
先熟悉下HandlerThread的一般用法。我们创建一个如下所示的Activity:
package com.example.handlethreaddemo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class MainActivity extends Activity
{
private Looper mLooper;
private MyHandler mHandler;
private static final String TAG = "MainActivity";
private static class MyHandler extends Handler
{
public MyHandler(Looper looper)
{
super(looper);
}
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 1:
Log.i(TAG, "当前线程是"+Thread.currentThread().getName()+",TEST 1");
break;
case 2:
Log.i(TAG, "TEST 2");
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建HandlerThread对象
HandlerThread myHandleThread = new HandlerThread("HandlerThread<子线程>");
//启动HandlerThread---->内部将启动消息循环
myHandleThread.start();
//获取Looper
mLooper = myHandleThread.getLooper();
//构造Handler,传入子线程中的Looper
mHandler = new MyHandler(mLooper);
/*
* 注:经过上述步骤,Handler将绑定子线程的Looper和MessageQueue.
* 也就是说handleMessage最终由子线程调用
* */
mHandler.sendEmptyMessage(1);
Log.i(TAG,"当前线程是:"+Thread.currentThread().getName());
}
}
使用HandlerThread内部提供的Looper对象构造Handler对象,然后在ui线程中向Handler发送消息。log日志如下:
可见发送消息的线程为UI线程,而处理消息的线程为子线程,也就是说,我们在
子线程中创建了消息循环。
一般情况下,我们总是在UI线程中创建Handler对象,并使用界面组件提供的默认Looper,这个Looper绑定在UI线程上。所以我们在线程中向Handler发送消息时,最终的处理是在主线程中进行的。但正如开篇所说,我们有时需要构建常驻的子线程以不定期执行计算型任务,这时在子线程中创建消息循环将非常有用。
二、HandlerThread源码剖析
HandlerThread源码十分精简。
HandlerThread继承自java.lang.Thread,并封装了Looper对象:
int mPriority;//优先级
int mTid = -1;//线程标志
Looper mLooper;//消息循环
可通过构造器注入线程优先级,默认优先级为Process.THREAD_PRIORITY_DEFAULT
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
核心逻辑为run方法(复写Thread类的run方法):
public void run() {
mTid = Process.myTid();
Looper.prepare();//创建Looper对象
synchronized (this) {
mLooper = Looper.myLooper();//获取与本线程绑定的Looper
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();//回调接口,默认为空实现。
Looper.loop();//启动消息循环--->may be blocked
mTid = -1;
}
外界可通过getLooper方法获取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();//异步等待Looper准备好
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
如果调用getLooper方法时,Looper未准备好,那么将会阻塞线程,直到准备好Looper对象。
外界可调用quit方法终止消息循环:
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();//内部调用looper类的quit
return true;
}
return false;
}
附:
Looper类相信大家都不陌生,这里顺便简单提下(之前写过Handler和Looper):
Looper.prepare方法将会创建一个Looper对象(Looper类的构造器为私有,不可new),并将其放到ThreadLocal中,意为线程局部变量:
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.myLooper方法返回与本线程绑定的Looper,正是刚创建的Looper:
public static Looper myLooper() {
return sThreadLocal.get();
}
Looper.loop方法将启动消息循环,不断从其内部封装的消息队列MessageQueue中取出消息,交由Handler执行。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
没有消息时,消息队列会阻塞。
以上就是HandlerThread的全部内容。