android handlerthread 线程管理,Android必读之HandlerThread

本文介绍了如何在自定义Thread中使用Handler进行有序的通信,展示了HandlerThread的优势,并对比了自定义实现与HandlerThread的使用方法。重点讲解了Looper的准备、退出机制,以及如何避免内存泄露。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HandlerThread是Thread的子类,主要特点就是为我们主动封装了Looper,这样我们就可以和Handler结合在一起使用,利用Handler的消息机制原理为我们更加有序高效的管理Thread通信和其它逻辑,这也为什么我们通常在自定义的Thread中使用Handler的原因。

首先我们先了解一下自定义Thread如何使用Handler,下面是完整Kotlin代码:

class MyThread() : Thread() {

var handler: Handler? = null;

override fun run() {

super.run()

Looper.prepare();//准备looper

initHandler();

//处理耗时操作,比如请求API,大量数据读写等

Log.d("MyThread", "MyThread-开始处理耗时逻辑");

getWeather()

//开始处理消息,确保在loop方法放在最后,因为这是无限循环,后面的代码不会执行

//当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行

//逻辑运行完成后调用quit或者quitSafely退出,否则会造成这个Thread会一直运行,从而造成内存泄露

Looper.loop();

}

fun initHandler() {

handler = Handler(object : Handler.Callback {

override fun handleMessage(msg: Message?): Boolean {

when (msg!!.what) {

0 -> {

Log.d("MyThread", "MyThread-Success");

handler!!.sendEmptyMessage(2)

}

1 -> {

Log.d("MyThread", "MyThread-Failed");

handler!!.sendEmptyMessage(2)

}

2 -> {

Log.d("MyThread", "MyThread-结束");

handler!!.looper.quitSafely();

}

}

return true;

}

})

}

fun getWeather() {

var response = HttpUtils.getInstance().requestWeather();

if (response != null) {

var result: String = response.body()!!.string();

Log.d("MyThread", result);

handler!!.sendEmptyMessage(0)

} else {

handler!!.sendEmptyMessage(1)

}

}

}

新建的Thread中没有Looper,需要我们指定或者使用Looper.prepare()新建一个,看一下prepare的源码就知道了:

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

}

如果没有指定Looper就创建Handler会报以下Exception:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

at android.os.Handler.(Handler.java:204)

at android.os.Handler.(Handler.java:132)

总结以上代码我们发现如果我们在自定义的Thread中使用Handler需要我们主动去实现Looper相关的功能,还是比较麻烦的,所以Android已经为我准备了HandlerThread类,已经封装好了Looper的逻辑,看一下Handler 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;

}

Handler Thread使用起来也非常简单:

//var为可变变量 和val为常量相当于final

val handlerThread = HandlerThread("MyHandler");

var handler: Handler? = null;

fun initHandlerThread() {

handlerThread.start();

val looper = handlerThread.looper;

//handler运行在handlerThread线程中,不能直接操作UI

handler = object : Handler(looper) {

override fun handleMessage(msg: Message?) {

super.handleMessage(msg)

when (msg!!.what) {

0 -> {

getWeather()

}

1 -> {

Log.d("HandlerThread", "HandlerThread-退出");

handlerThread.quitSafely()//安全推送线程

}

}

}

};

}

/**

* 因为getWeather方法运行在handlerThread线程中,所以不用担心ANR,使用同步方式请求API

*/

fun getWeather() {

var response = HttpUtils.getInstance().requestWeather();

if (response != null) {

var result: String = response.body()!!.string();

Log.d("HandlerThread", result);

}

handler!!.sendEmptyMessage(1)

}

在使用HandlerThread时我们一定要注意需要我们及时退出Looper,否则容易造成内存泄露。Looper退出的方法有两个quit和quitSafely,HandlerThread中源码如下:

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中的源码:

public void quit() {

mQueue.quit(false);

}

public void quitSafely() {

mQueue.quit(true);

}

都是调用MessageQueue的quit的方法,只不过一个传了false,一个传了true,区别就是quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。

quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。如果有兴趣可以参考一下下面的源码:

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);

}

}

private void removeAllMessagesLocked() {

Message p = mMessages;

while (p != null) {

Message n = p.next;

p.recycleUnchecked();

p = n;

}

mMessages = null;

}

private void removeAllFutureMessagesLocked() {

final long now = SystemClock.uptimeMillis();

Message p = mMessages;

if (p != null) {

if (p.when > now) {

removeAllMessagesLocked();

} else {

Message n;

for (;;) {

n = p.next;

if (n == null) {

return;

}

if (n.when > now) {

break;

}

p = n;

}

p.next = null;

do {

p = n;

n = p.next;

p.recycleUnchecked();

} while (n != null);

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值