Android消息机制之HandlerThread

概述

HandlerThread 本质是一个线程,它继承自 Thread。不过特殊的是,它内部封装了 Handler 和 Looper 来进行消息的分发、循环以及处理。

那么 HandlerThread 产生的背景是什么呢?想象一种场景,我们知道,耗时任务需要在子线程中进行,而线程的创建和销毁是非常消耗系统资源的,如果当任务 A 执行完了后,如果还需要执行任务 B, 那么就还需要创建一个新的子线程进行。这样性能问题就会凸显。为此,可以子线程中创建一个轮询器 Looper,当有新任务时,Looper 就开启并处理,否则就阻塞,直到下一个耗时任务的到来。因此,HandlerThread 内部封装了 Handler 和 Looper ,可以避免多次创建和销毁线程带来的性能问题。

Android 中的 IntentService 内部就使用了 HandlerThread 。 IntentService 的 onCreate()中会创建子线程的 Handler :ServiceHandler,在ServiceHandlerhandleMessage()方法中调用onHandleIntent(),因此,onHandleIntent()才会运行在子线程。

示例

对于 Handler,我们一般的使用是在主线程中创建 Handler,然后子线程通过 Handler 来发送消息,主线程接受到消息后,就可以在 handleMessage() 中处理消息,如更新UI等。那么,主线程能否向子线程发送消息呢?子线程能否向子线程发送消息呢?答案是肯定的。

下面这个例子,展示了如何利用 HandlerThread 进行主线程与子线程之间相互通信、子线程和子线程之间通信。布局如下图所示(比较简单,就不上代码了):
在这里插入图片描述

public class HandlerThreadActivity extends Activity implements View.OnClickListener {

    //分别对应上图三个按钮
    private TextView mTvSub2Main, mTvMain2Sub, mTvSub2Sub;
    private Handler mMainHandler, mSubHandler;
    private HandlerThread mHandlerThread;

    private static final int SUB_TO_MAIN = 1;
    private static final int MAIN_TO_SUB = 2;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        mTvSub2Main = findViewById(R.id.tv_handler_sub_to_main);
        mTvMain2Sub = findViewById(R.id.tv_handler_main_to_sub);
        mTvSub2Sub = findViewById(R.id.tv_handler_sub_to_sub);

        mTvSub2Main.setOnClickListener(this);
        mTvMain2Sub.setOnClickListener(this);
        mTvSub2Sub.setOnClickListener(this);

        //创建HandlerThread实例
        mHandlerThread = new HandlerThread("handler_thread");
        //开启新的子线程
        mHandlerThread.start();
        //将HandlerThread与Handler绑定:利用mHandlerThread获取子线程的Looper,创建子线程的Handler实例
        mSubHandler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case SUB_TO_MAIN:
                        Log.e("twj", msg.what + "  SubHandler 接收线程: " + Thread.currentThread().getName());
                        break;
                    case MAIN_TO_SUB:
                        Log.e("twj", msg.what + "  SubHandler 接收线程: " + Thread.currentThread().getName());
                        break;
                }
            }
        };

        //利用主线程的Looper,创建对应的主线程Handler
        mMainHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case SUB_TO_MAIN:
                        Log.e("twj", msg.what + "  MainHandler 接收线程: " + Thread.currentThread().getName());
                        break;
                    case MAIN_TO_SUB:
                        Log.e("twj", msg.what + "  MainHandler 接收线程: " + Thread.currentThread().getName());
                        break;
                }
            }
        };
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_handler_sub_to_main:
                Thread thread1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //1、子线程发消息主线程处理消息
                        Log.e("twj", "发送线程: "+Thread.currentThread().getName());
                        mMainHandler.sendEmptyMessage(SUB_TO_MAIN);
                    }
                });
                thread1.start();
                break;
            case R.id.tv_handler_main_to_sub:
                //2、主线程发消息子线程处理消息
                Log.e("twj", "发送线程: "+Thread.currentThread().getName());
                mSubHandler.sendEmptyMessage(MAIN_TO_SUB);
                break;
            case R.id.tv_handler_sub_to_sub:
                Thread thread2 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //3、子线程发消息子线程处理消息
                        Log.e("twj", "发送线程: "+Thread.currentThread().getName());
                        mSubHandler.sendEmptyMessage(SUB_TO_MAIN);
                    }
                });
                thread2.start();
                break;
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //养成好习惯:在不需要HandlerThread的时候需要手动停止掉
        mHandlerThread.quit();
    }
}

分别点击三个按钮,运行结果如下:

 2019-02-22 17:54:42.560 16301-16759/com.hust_twj.zademo E/twj: 发送线程: Thread-31
2019-02-22 17:54:42.561 16301-16301/com.hust_twj.zademo E/twj: 1  MainHandler 接收线程: main
2019-02-22 17:54:44.372 16301-16301/com.hust_twj.zademo E/twj: 发送线程: main
2019-02-22 17:54:44.373 16301-16730/com.hust_twj.zademo E/twj: 2  SubHandler 接收线程: handler_thread
2019-02-22 17:54:45.655 16301-16771/com.hust_twj.zademo E/twj: 发送线程: Thread-32
2019-02-22 17:54:45.655 16301-16730/com.hust_twj.zademo E/twj: 1  SubHandler 接收线程: handler_thread

从打印结果可以看到,利用 HandlerThread,可以实现任意两个线程之间的通信。

源码分析

HandlerThread 源码比较短,加上所有的注释才只有160 来行,但是都是浓缩的精华:

/**
 * 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;
    int mTid = -1;
    Looper mLooper;
    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;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     * 可以重写该方法,但是需要在调用Loop.loop()方法之前调用
     */
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        //获得当前线程的id
        mTid = Process.myTid();
        //初始化looper
        Looper.prepare();
        //同步代码块
        synchronized (this) {
            mLooper = Looper.myLooper();、
            //阻塞--等待机制
            //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper()中的wait(),结束阻塞
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现
        onLooperPrepared();
        //开启循环,Handler从消息队列中处理消息
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    //该方法主要作用是获得当前HandlerThread线程中的mLooper对象
    public Looper getLooper() {
        //如果线程不是活动的,则直接返回null
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        //同步代码块:如果线程已经启动,但是Looper还未创建的话,就阻塞等待,直到run()中的Looper对象创建成功
        synchronized (this) {
            //阻塞-等待机制
            //开启循环,调用wait()去阻塞线程,当run()中的notifyAll()调用之后,
            //通知当前线程的wait方法结束阻塞,跳出循环,确保已经创建了mLooper对象。
            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;
    }

    public int getThreadId() {
        return mTid;
    }
}

可以看到,HandlerThread 继承了 Thread,构造方法有两个,可以传入线程名称以及线程优先级。
对于 run()方法,其内部调用 Looper.prepare();Looper.loop();来创建 Looper 对象并进行消息的轮询,也就是说,在使用 HandlerThread 时,即便已经是子线程,也不需要再手动创建 Looper了(如果是在子线程中创建 Handler,就需要手动创建Looper,即依次调用 Looper.parpare()Looper.loop())。在 synchronized 同步代码块中,有个 notifyAll(),而 getLooper() 中有个 wait(),这是为什么呢?在获得 mLooper 对象的时候存在一个同步的问题,只有当线程创建成功并且 Looper 对象也创建成功之后才能获得 mLooper 的值。这里等待方法waitnotifyAll()方法共同解决同步问题。

在HandlerThread 不使用的时候,需要调用退出方法quit()/quitSafely()

总结

  • HandlerThread 本质是一个线程类,继承自 Thread;
  • HandlerThread 有自己的内部 Looper 对象,可以进行 Looper 循环;
  • 通过获取 HandlerThread 的 looper 对象传递给 Handler,可以在 handlerMessage()中执行异步任务;
  • 优点是减少了对性能的消耗,缺点是不能同时进行多任务的处理,需要等待处理,效率较低;
  • 与线程池注重并发不同,HandlerThread 是一个串行队列,HandlerThread 背后已只有一个线程。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值