Android基础-HandlerThread基本使用与源码分享

上文讲服务相关的文章中,我们有用HandlerThread去开启一个工作线程,这篇文章就来介绍下HandlerThread。

HandlerThread是什么东西呢?了解一个类最好的方法就是查看类的定义,所以我们就看一下HandlerThread是如何定义的吧。查看类的定义时有这样一段话:

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的线程。

么我们在什么时候需要用到它呢?为了让多个线程之间能够方便的通信,我们会使用Handler实现线程间的通信。这个时候我们手动实现的多线程+Handler的简化版就是我们HandlerThrea所要做的事了。

下面我们首先看一下HandlerThread的基本用法:

现在一个线程去开启工作线程与new handler:

HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
        mHandlerThread.start();

        
        final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.i("tag", "接收到消息:" + msg.obj.toString());
            }
        };

 再找另外一个线程去发送消息:

 Message msg = new Message();
                msg.obj = "11111";
                mHandler.sendMessage(msg);

                msg = new Message();
                msg.obj = "2222";
                mHandler.sendMessage(msg);

这样我们就做到了线程间的消息通讯:

这里方便就方便在我们在两个子线程去进行通讯也不用我们去创建Looper,因为HandlerThread里面已经封装好了。

HandlerThread 源码解析

HandlerThread 的源码非常简单,只有几个方法

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;
    }
    
  	// 构造函数二,线程名和线程优先级。由Process提供而不是Thread
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
  	// 回调函数
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid(); // 获取当前线程ID
        Looper.prepare(); // 创建Looper和MessageQueue
        synchronized (this) {
            mLooper = Looper.myLooper(); // 获取Looper
            notifyAll();
        }
        Process.setThreadPriority(mPriority); // 设置线程优先级
        onLooperPrepared();
        Looper.loop(); // 开启loop循环
        mTid = -1;
    }
    
  	// 加锁获取Looper对象
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        // 因为是异步线程,所以要加锁等待Looper对象初始化完成
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }


 		// 获取根据Looper对象创建的Handler,隐藏API
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

  	// 马上终止Looper,不管任务有没有执行完成
    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;
    }

		// 返回线程ID
    public int getThreadId() {
        return mTid;
    }
}

就几个方法,注释写的也很清楚了。创建 HandlerThread 有两个构造函数,我们只使用一个参数的构造函数来创建对象就好了,当调用 start 方法的时候,HandlerThread 的 run 方法就会马上被调用,在 run 方法中调用了 Looper.prepare 方法创建一个 Looper 对象,并在创建 Looper 的时候也创建了一个 MessageQueue 对象。

然后使用 synchronized 锁住了代码块,为什么这里要加锁,并且要调用 notifyAll 方法呢?

这还要从另一个方法 getLooper 说起,我们在使用 Looper 创建 Handler 对象时,调用了 getLooper 方法,它是在主线程中执行的,而创建 Looper 对象又是在 run 方法这个子线程中执行的,因为它们处于不同的线程中,这样就无法保证在获取 Looper 对象时一定初始化完成了。所以就需要使用锁来保证获取 Looper 对象的时候一定初始化完成了,如果没有初始化完成,那么就继续等待 Looper 初始化完成再返回。

获取到返回的 Looper 对象赋值给了 mLooper 变量后,调用了回调方法 onLooperPrepared 方法,它是一个空方法,如有需要可以在子类中重写该方法,接着调用了 Looper.loop 方法开启循环。

总结:

  • HandlerThread本质上是一个Thread对象,只不过其内部帮我们创建了该线程的Looper和MessageQueue;

  • 通过HandlerThread我们不但可以实现UI线程与子线程的通信同样也可以实现子线程与子线程之间的通信;

  • HandlerThread在不需要使用的时候需要手动的回收掉;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值