@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: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 | 备注 |
---|---|---|
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就会取出消息并处理消息,当没有消息时就会阻塞。
共同学习,写下你的评论
评论加载中...
作者其他优质文章