Android多线程-HandlerThread用法与源码解析

本文深入解析了Android中的HandlerThread类,探讨了其在多线程通讯中的应用,通过源码分析展示了HandlerThread的工作原理,并提供了使用示例。

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

使用HandlerThread好处

在Android开发中,我们经常使用多线程编程。而多线程有多种方式实现。其中我们用得最多、也是最早接触的是使直接开一个线程Thread

new Thread(){
    @Override
    public void run() {
        //do something here
    }
}.start();

先抛开这样开线程的弊端,因为在有时做一些简单的任务时,这样写确实能减少代码量;我们先说说线程间通讯。Android自带提供HandlerLooper的组合来实现。使用方法相信大家都很熟悉了。而HandlerThread就是为了实现多线程之间通讯的一个类,可以减少一定的代码量。

HandlerThread源码解析

首先,我们先看看源码(不感兴趣可以跳过,下方有使用方法解析):

package android.os;

/**
 * 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`的`Thread`,然而`start()`还是需要被调用
 *
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    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.
     *
     * 输入的优先级是来自`android.os.Process`里的,而不是来自`java.lang.Thread`里的
     *
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

这是HandlerThread类的开头,我们可以看到,这个类属于android.os包,属于sdk内的类,使用方便,无需另外导入。
该类继承于Thread类,本质上是一个线程。
该类提供两个构造方法,单参数构造方法,输入参数为线程名字,双参数构造方法输入线程名字以及线程优先级,这里需要注意一点,输入的优先级是android.os.Process里的,而不是java.lang.Thread里的。

我们再往下看代码:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

这是核心部分,当线程被启动后,调用该run()方法。首先,记录了该线程的id号,然后调用Looper.prepare(),创建该线程上的looper对象。
接着对自身对象加锁,并获取该线程上的looper引用,并调用notifyAll(),唤醒其他正在等待该对象的线程。做这一步的原因,我们后面再做解释。
然后在进程里对当前线程设置优先级。
最后调用Looper.loop(),启动looper的消息队列循环。
到此,该类以及基本可以运行了

我们再往下看代码:

/**
 * This method returns the Looper associated with this thread. If this thread not been started
 * or for any reason is isAlive() returns false, this method will return null. If this thread 
 * has been started, this method will block until the looper has been initialized. 
 * 
 * 该方法会返回一个关联该线程的Looper
 * 如果该线程还未启动,或者某种原因isAlive返回false,这个方法会会返回null值
 * 如果线程已经启动,这个方法会阻塞,直到looper被初始化
 * 
 * @return The 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;
}

从注释中,我们可以看到,该方法是返回一个和该类线程相关的looper,首先判断该线程是否正在运行,若否,则返回一个空值(线程未启动,当然没有关联的looper)。
接着对自身对象加锁,再次判断线程是否正在运行,且mLooper是否已经赋值。这里用到的方法是双重检测,和单例模式中的双重检测是一样的。若线程已经在运行,但mLooper未赋值,那就在该线程等待。
我们可以和上面的run方法联系起来了。直到run()方法执行到notifyALL(),才被唤醒,继续判断,直到mLooper赋值,返回mLooper
这样写的目的是为了防止多线程操作下,防止某个线程从一个已经运行的HandlerThread但还未完成run方法的对象里,获取到空的looper引用。

HandlerThread用法

那么我们平时怎么使用HandlerThread这个类呢?
首先我们可以创建一个HandlerThread类实例,并运行该线程,那么该线程就开始进入等待消息的状态:

handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();

接着我们可以创建一个和该线程的Handler,里面实现我们业务需求的执行的方法,构造方法里就可以传入我们HandlerThread类实例的looper,这样,handler就和我们的线程关联在一起了:

handler =new Handler(handlerThread.getLooper()){
    @Override
    public void handleMessage(Message msg) {
        //这里可以实现我们的业务需求
        Log.i(TAG,"receive msg:"+msg.what);
    }
};

接下来,就和我们平时使用handler一样使用了,该任务就会在HandlerThread实例的线程运行了:

handler.sendEmptyMessage(123);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值