Android多线程之HandlerThread


@author:小马快跑
@email:mqcoder90@gmail.com
@github:https://github.com/crazyqiang


HandlerThread的介绍及用法

HandlerThread继承自Thread,内部实现了初始化了Looper,并创建了消息队列,接着调用了Looper.loop()开启了消息循环,这样HandlerThread就可以处理通过Handler传递过来的Message了,因为HandlerThread中的run方法是无限循环,当有消息过来时处理消息,没有消息时就会阻塞。当明确不需要HandlerThread时,可以调用quit或者quitSafely (API 18以上使用)来尝试终止线程。

先看实现的一个效果图:

HandlerThread.gif
完整代码已上传github:Android多线程之HandlerThread

来分析实现代码,先定义对象:

 private HandlerThread handlerThread;
 private Handler mainHandler;
 private Handler uiHandler;

初始化:

 handlerThread = new HandlerThread("handler_thread");
 handlerThread.start();
 //在主线程初始化,传入的是HandlerThread中的Looper
 mainHandler = new Handler(handlerThread.getLooper()) {
     @Override
     public void handleMessage(Message msg) {
         //Handler是在HandlerThread所在的子线程线程中处理Message
         switch (msg.what) {
             case MSG_UPDATE:
                 if (isStop) return;
                 try {
                     //更新UI
                     String result = String.valueOf(new Random().nextInt(9000) + 1000);
                     sendMsg(UI_UPDATE, result, uiHandler);
                     //延迟2秒
                     Thread.sleep(2000);
                     //循环发送消息
                     mainHandler.sendEmptyMessage(MSG_UPDATE);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 break;
         }
     }
 };

首先,初始化HandlerThread并通过handlerThread.getLooper()关联一个在UI线程初始化的mainHandler,这样就可以通过mainHandler在主线程中向HandlerThread中发送消息了,这里要注意一下,mainHandler中的handleMessage()方法是在HandlerThread子线程中执行的,为什么会在子线程中执行呢?因为在初始化mainHandler时传入的是HandlerThread的Looper,而mainHandler是把消息发送到HandlerThread中去,HandlerThread在执行Looper.loop()方法后会循环取出消息并处理消息,所以mainHandler中的handleMessage()方法是在HandlerThread子线程中执行的,那么处理完消息后怎么更新到UI线程呢?

 //在主线程初始化,传入的是主线程中的Looper
 uiHandler = new Handler(Looper.getMainLooper()) {
     @Override
     public void handleMessage(Message msg) {
         //在主线程中处理Message
         switch (msg.what) {
             case UI_UPDATE:
                 //更新验证码
                 String result = (String) msg.obj;
                 tv_random.setText(result);
                 break;
         }
     }
 };

我们在主线程中初始化了另一个uiHandler 并传入了主线程的Looper,所以此时最后处理消息的回调方法handleMessage()是在主线程中执行的,当HandlerThread处理完逻辑后,通过uiHandler把结果发到主线程中,就可以愉快地来更新UI了,最后别忘了关闭线程:

@Override
 protected void onDestroy() {
     if (SDK_INT >= 18) {
         handlerThread.quitSafely();
     } else {
         handlerThread.quit();
     }
     super.onDestroy();
 }

HandlerThread API

返回结果HandlerThread备注
LoopergetLooper()返回和HandlerThread关联的Looper
intgetThreadId()返回HandlerThread线程的标识符,参见Process.myTid()
booleanquit()立即停止Looper的循环,即使messageQueue中有消息也不再处理,在调用此方法后,任何传递Message的方法 (如sendMessage(Message)) 都将失败并返回false
booleanquitSafely()当messageQueue中没有Message后,在调用此方法后立即终止Looper,任何传递Message的方法 (如sendMessage(Message)) 都将失败并返回false
voidrun()如果HandlerThread使用单独的Runnable来构造,将执行此方法

HandlerThread源码分析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    //初始化HandlerThread
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

   //初始化HandlerThread
   public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        //调用Looper.prepare()初始化Looper 并把Looper放到sThreadLocal中,sThreadLocal可以在不同线程中保存对象副本
        //在Looper的构造方法中就初始化了一个messageQueue,用来存放传入的消息
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        //开始循环从messageQueue中取出消息并处理消息,无消息会阻塞,有消息来时就会唤醒
        Looper.loop();
        mTid = -1;
    }

    //返回的即是run方法中产生的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的循环,即使messageQueue中有消息也不再处理,在调用此方法后,任何传递Message的
    //方法 (如sendMessage(Message)) 都将失败并返回false
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    //当messageQueue中没有Message后,在调用此方法后立即终止Looper,任何传递Message的
    //方法 (如sendMessage(Message)) 都将失败并返回false
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

源码很简单,首先HandlerThread继承了Thread,所以HandlerThread本质上还是一个线程,只不过在run()方法中又初始化了Looper和MessageQueue,这样当外界通过Handler向HandlerThread传入消息后,HandlerThread就会取出消息并处理消息,当没有消息时就会阻塞。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Android多线程是指在Android应用程序中同时执行多个线程的技术。在Android开发中,多线程主要用于处理耗时操作,以避免阻塞主线程(也称为UI线程),从而提高应用的响应性能。 在Android中,常用的多线程技术包括以下几种: 1. AsyncTask:这是一种轻量级的异步任务类,适用于较简单的后台任务。它封装了线程的管理和与UI线程的交互,可以在UI线程中执行一些耗时操作,如网络请求、数据库查询等。 2. HandlerThread:这是一种带有消息队列的线程类。它可以用来创建一个后台线程,并通过Handler与UI线程进行通信。通常用于执行需要长时间运行的任务或周期性任务。 3. ThreadPoolExecutor:这是一个线程池类,可以管理多个线程并发执行任务。通过使用线程池,可以有效地重用线程、控制并发数量、管理线程的生命周期等。 4. IntentService:这是一种继承自Service的特殊服务类,用于执行后台任务。它会自动创建工作线程来处理任务,并在任务完成后自动停止。 5. RxJava:这是一个响应式编程库,可以简化多线程编程。通过使用观察者模式和链式调用,可以方便地实现异步操作和线程切换。 除了以上几种常用的多线程技术,还可以使用Java原生的Thread类来创建和管理线程,但需要注意在UI线程中的使用,避免阻塞UI的响应。 在使用多线程时,需要注意线程安全性,避免出现数据竞争和死锁等问题。同时,也要合理地管理线程的生命周期,确保在不需要时及时停止和释放资源。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小马快跑_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值