博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android多线程之HandlerThread
阅读量:5740 次
发布时间:2019-06-18

本文共 5108 字,大约阅读时间需要 17 分钟。


@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以上使用)来尝试终止线程。

先看实现的一个效果图:

完整代码已上传github:

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

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 备注
Looper getLooper() 返回和HandlerThread关联的Looper
int getThreadId() 返回HandlerThread线程的标识符,参见Process.myTid()
boolean quit() 立即停止Looper的循环,即使messageQueue中有消息也不再处理,在调用此方法后,任何传递Message的方法 (如sendMessage(Message)) 都将失败并返回false
boolean quitSafely() 当messageQueue中没有Message后,在调用此方法后立即终止Looper,任何传递Message的方法 (如sendMessage(Message)) 都将失败并返回false
void run() 如果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就会取出消息并处理消息,当没有消息时就会阻塞。

转载于:https://juejin.im/post/5a33e7c26fb9a0451171312d

你可能感兴趣的文章
andriod第三课------Intent、后台服务与线程
查看>>
理解Java对象序列化
查看>>
作业派NABCD的特点分析
查看>>
渗透测试-内网渗透笔记
查看>>
aapt命令获取apk详细信息(包名、版本号、版本名称、兼容api级别、启动Activity等)...
查看>>
C# 自定义控件入门
查看>>
指令 作用域绑定
查看>>
【转】web测试总结--用户体验测试
查看>>
斐波那契数列的递归实现和顺序实现
查看>>
IntelliJ IDEA 2017 主题安装及配置
查看>>
MTU设置
查看>>
gdi资料
查看>>
mysql 知识整理
查看>>
异常的定位与解决
查看>>
男人的小金库藏在哪里?——公共数据集Model
查看>>
php mysql_affected_rows获取sql执行影响的行数
查看>>
php读取zip文件(删除文件,提取文件,增加文件)实例
查看>>
理解Ajax
查看>>
mysql主从双机复制备份
查看>>
ASP.NET站点Web部署(一键发布的实现)
查看>>