Android多线程之HandlerThread源码解析

41次阅读

共计 5839 个字符,预计需要花费 15 分钟才能阅读完成。

一、概述
先来了解一下 HandlerThread 的几个特性

HandlerThread 继续于 Thread, 本身就是一个线程类
HandlerThread 在内部维护了自己的 Looper 对象,所以可以进行 Looper 循环
创建 HandlerThread 后需要先调用 HandlerThread.start() 方法再向其下发任务,通过 run() 方法来创建 Looper 对象
通过传递 HandlerThread 的 Looper 对象给 Handler 对象,从而可以通过 Handler 来向 HandlerThread 下发号是任务

二、使用方式
再来看 HandlerThread 的使用方式
创建 HandlerThread 并调用 start() 方法,使其在子线程内创建 Looper 对象
HandlerThread handlerThread = new HandlerThread(“HandlerThread”);
handlerThread.start();

然后以 HandlerThread 内部的 Looper 对象为参数创建一个 Handler, 通过 Handler 向子线程发送 Message, 以此下发耗时任务,消息的接受者与任务的处理者则由回调函数 ChildCallback 来完成
Handler childThreadHandler = new Handler(handlerThread.getLooper(), new ChildCallback());

//Callback 运行于子线程
private class ChildCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
// 在此可以进行耗时操作
// 如果需要更新 UI,则需要通过主线程的 Handler 来完成
return false;
}
}

完整的实列代码如下所示
public class MainActivity extends AppCompatActivity {

private static final String TAG = “MainActivity”;

//Callback 运行于子线程
private class ChildCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
// 在此可以进行耗时操作
// 如果需要更新 UI,则需要通过主线程的 Handler 来完成
Log.e(TAG, “ChildCallback 当前线程名:” + Thread.currentThread().getName() + ” ” + “ 当前线程 ID:” + Thread.currentThread().getId());
Log.e(TAG, “ 耗时任务开始 ”);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, “ 耗时任务结束 ”);
// 通知界面更新 UI
uiHandler.sendEmptyMessage(1);
return false;
}
}

// 运行于主线程的 Handler,用于更新 UI
@SuppressLint(“HandlerLeak”)
private Handler uiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.e(TAG, “uiHandler 当前线程名:” + Thread.currentThread().getName() + ” ” + “ 当前线程 ID:” + Thread.currentThread().getId());
Toast.makeText(MainActivity.this, “ 耗时操作完成 ”, Toast.LENGTH_LONG).show();
}
};

// 用于向子线程发布耗时任务的 Handler
private Handler childThreadHandler;

private HandlerThread handlerThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread(“HandlerThread”);
handlerThread.start();
childThreadHandler = new Handler(handlerThread.getLooper(), new ChildCallback());
Log.e(TAG, “onCreate 当前线程名:” + Thread.currentThread().getName() + ” ” + “ 当前线程 ID:” + Thread.currentThread().getId());
}

public void startTask(View view) {
childThreadHandler.sendEmptyMessage(1);
}

@Override
protected void onDestroy() {
super.onDestroy();
handlerThread.quit();
childThreadHandler.removeCallbacksAndMessages(null);
}

}

程序运行后的日志如下所示,可以看出各个方法在调用时所处的线程
06-22 02:51:41.779 21977-21977/com.summer.myapplication E/MainActivity: onCreate 当前线程名:main 当前线程 ID:2
06-22 02:51:44.927 21977-21995/com.summer.myapplication E/MainActivity: ChildCallback 当前线程名:HandlerThread 当前线程 ID:497
06-22 02:51:44.928 21977-21995/com.summer.myapplication E/MainActivity: 耗时任务开始
06-22 02:51:49.930 21977-21995/com.summer.myapplication E/MainActivity: 耗时任务结束
06-22 02:51:49.930 21977-21977/com.summer.myapplication E/MainActivity: uiHandler 当前线程名:main 当前线程 ID:2

三、源码分析
先看下 HandlerThread 的类声明
Thread 的子类
public class HandlerThread extends Thread
两个构造函数,可以传入的参数分别是线程名和线程优先级
public HandlerThread(String name) {
super(name);
// 使用默认的线程优先级
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

public HandlerThread(String name, int priority) {
super(name);
// 使用自定义的线程优先级
mPriority = priority;
}

看下 run() 方法
@Override
public void run() {
mTid = Process.myTid();
// 触发当前线程创建 Looper 对象
Looper.prepare();
synchronized (this) {
// 获取 Looper 对象
mLooper = Looper.myLooper();
// 唤醒在等待的线程
// 唤醒 getLooer() 中可能还处于等待状态的线程
notifyAll();
}
// 设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
// 开启消息循环
Looper.loop();
mTid = -1;
}

Looper.prepare() 方法用于为当前线程创建一个 Looper 对象,在主线程需要依赖此 Looper 对象来构建一个 Handler 对象,通过 Handler 对象来向子线程下发耗时任务
之后可以看到有一个同步代码块,在当中调用了 notifyAll() 来唤醒等待线程,那该唤醒的又是那个线程呢?这里需要明确各个方法是运行于那个线程,run() 方法肯定是运行在子线程中,但用于想 HandlerThread 下发任务的 Handler 是初始化于主线程,因此 getlooper() 方法也是运行于主线程的。由于是两个不同的线程,run() 方法和 getLooper() 的运行先后顺序是不明确的,因此 getLooper() 方法需要确保 Looper 对象不为 null 时才返回,否则将一直阻塞等待 Looper 对象初始化完成
// 获取与当前线程关联的 Looper 对象
// 因为 getLooper() 方法可能先于 run() 被调用,此时就需要先等待 Looper 对象被创建
public Looper getLooper() {
// 如果当前线程未在运行,则返回 null
if (!isAlive()) {
return null;
}
synchronized (this) {
// 如果当前线程已处理运行状态(已调用 start() 方法)且 Looper 对象还未创建
// 则调用 wait() 方法释放锁,等待 Looper 对象创建
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}

Looper 对象初始化完成后,就需要调用 Looper.loop() 来开启消息循环,至此 HandlerThread 的初始化操作就完成了
HandlerThread 的完整源码注释
package android.os;

import android.annotation.NonNull;
import android.annotation.Nullable;

/**
* 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.
*/
public class HandlerThread extends Thread {

// 线程优先级
int mPriority;

// 线程 ID
int mTid = -1;

// 当前线程持有的 Looper 对象
Looper mLooper;

// 包含当前 Looper 对象的 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;
}

// 在 Looper 循环启动前调用
// 此处是空实现,留待子类重写
protected void onLooperPrepared() {
}

@Override
public void run() {
mTid = Process.myTid();
// 触发当前线程创建 Looper 对象
Looper.prepare();
synchronized (this) {
// 获取 Looper 对象
mLooper = Looper.myLooper();
// 唤醒在等待的线程
// 唤醒 getLooer() 中可能还处于等待状态的线程
notifyAll();
}
// 设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
// 开启消息循环
Looper.loop();
mTid = -1;
}

// 获取与当前线程关联的 Looper 对象
// 因为 getLooper() 方法可能先于 run() 被调用,此时就需要先等待 Looper 对象被创建
public Looper getLooper() {
// 如果当前线程未在运行,则返回 null
if (!isAlive()) {
return null;
}
synchronized (this) {
// 如果当前线程已处理运行状态(已调用 start() 方法)且 Looper 对象还未创建
// 则调用 wait() 方法释放锁,等待 Looper 对象创建
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}

/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}

// 清空消息队列中所有的消息
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;
}

/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}

}

正文完
 0