本文我们将学习HandlerThread的实现原理,以及开发时,如何正确的使用它来实现我们的开发任务。
HandlerThread源码分析
设想这样一个场景:我们要在一个线程A中处理业务逻辑,在另一个线程B中,监听A的执行,并进行结果处理。这时我们使用HandlerThread就可以非常简单的实现该功能了。
通常我们的线程交互场景,都是UI线程中启动子线程,并且由子线程完成工作任务,最终结果交给UI线程。现在我们的使用场景是,在子线程中监控其他线程的执行结果(这里的其他线程可以是另一个子线程,也可以是UI线程),并在子线程中进行结果的处理。
通过描述,我们可以得出2点结论:第一,这个过程中,需要存在2个线程;第二,这两个线程需要进行数据传输(交互)。那么,我们很自然的就想到了Handler机制来实现该功能,但是我们自己在一个子线程中,使用Handler稍显麻烦一些,HandlerThread内置了Handler,简化了我们的操作。
HandlerThread构造函数和继承关系:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {//构造函数1
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {//构造函数2
super(name);
mPriority = priority;
}
}
逻辑解析:
- HandlerThread继承自Thread类,所以它本质上是一个线程类,可以实现线程相关的操作。
- 我们来看HandlerThread的构造函数,这里有2个重载版本。
- 第一个构造函数接收一个name参数,直接调用了super方法,为该线程命令,且线程优先级为Process.THREAD_PRIORITY_DEFAULT。
- 第二个构造函数接收2个参数,可实现线程命名,和设置线程的优先级。
HandlerThread的run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
逻辑解析:
- 我们在创建了HandlerThread实例之后,调用start()方法执行,ART虚拟机会帮我们创建一个线程对象,然后在子线程中执行run方法。
- run方法中,执行了Looper.prepare()方法,创建了一个Looper对象并绑定到该线程。
- 然后在同步块中,执行了mLooper的赋值,调用notifyAll通知Looper已创建完成。
- 调用Process.setThreadPriority方法设置线程优先级。
- 调用空方法onLooperPrepared,通常用于回调使用。
- 最后调用Looper.loop()方法,启动该线程的消息循环。
getLooper方法:
public Looper getLooper() {
if (!isAlive()) {//判断线程是否存活
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
//如果线程存活,但mLooper没有创建完成,则等待
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;//返回当前线程的Looper对象
}
逻辑解析:
- getLooper方法可以返回当前线程绑定的Looper对象,我们可以使用该对象作为参数,创建一个该线程的Handler对象,用于线程交互。
- getLooper方法首先会判断当前线程是否存活,如果存活,则继续。
- 如果线程存活,但Looper对象还没有创建完成,则调用wait方法进行等待(Looper创建完成后,会在HandlerThread的run方法中,调用notifyAll()通知,以继续执行当前逻辑)。
- 最后返回Looper对象即可。
HandlerThread的getThreadHandler方法
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
- 如果我们不想自己创建Handler对象,也可以使用HandlerThread为他们提供的Handler对象。
- getThreadHandler方法返回一个当前线程的Handler对象。
- 它是一个隐藏方法,我们在应用中不可调用。
HandlerThread的退出
//立即执行退出
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;
}
当不需要HandlerThread时,需要调用quit方法或quitSafely方法结束线程管理的Looper消息循环。
HandlerThread实战
HandlerThread的实现其实并不复杂,我们以一个简单Demo来看它的使用。
Demo
public class HandlerThreadTest {
private final static String TAG = "budaye";
public static final int HT_MSG = 1;
private HandlerThread mHandlerThread = new HandlerThread("myHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
private Handler mHandler = null;
public void startHandlerthread(){
mHandlerThread.start();
if (mHandler == null){
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case HT_MSG:
Log.d(TAG, "当前线程:" + Thread.currentThread());
Log.d(TAG, "收到其他线程发送过来的消息了");
break;
}
}
};
}
}
public void sendMessage() {
Log.d(TAG, "当前线程:" + Thread.currentThread());
Message msg = Message.obtain();
msg.what = HT_MSG;
mHandler.sendMessage(msg);
}
}
逻辑解析:
- 在HandlerThreadTest里,创建了一个HandlerThread对象。
- 调用startHandlerthread方法,开始了HandlerThread对象的线程消息循环,并且创建了一个mHandler对象,用于处理其他线程发送过来的消息。
- 我们可以在UI线程中调用sendMessage方法来发送给HandlerThread线程一个消息,并在mHandler对象的handleMessage方法中进行处理。
Demo日志输出
25208-25208/com.example.simpledemo D/budaye: 当前线程:Thread[main,5,main]
25208-25284/com.example.simpledemo D/budaye: 当前线程:Thread[myHandlerThread,5,main]
25208-25284/com.example.simpledemo D/budaye: 收到其他线程发送过来的消息了
我们分别在2个线程中输出了日志。
最佳实践&总结
- HandlerThread是一个异步处理的工具类,它可以帮助我们很轻松的实现异步线程处理。
- HandlerThread继承自Thread类,它的本质是一个线程类。
- HandlerThread实现原理非常简单,它利用了Handler原理,在内部了一个Looper循环,并绑定到当前线程中。
- 我们使用创建一个Handler对象,绑定到HandlerTHread对象所对应的Looper,并处理其他线程发送过来的消息。
- HandlerThread在构造方法中可以设置线程优先级,默认使用Process.THREAD_PRIORITY_DEFAULT作为默认优先级。
- 我们在应用过程中,不要大量使用HandlerThread来执行异步任务,这样会造成线程资源的浪费,大量的异步任务,建议使用线程池来进行操作。
- HandlerThread的线程优先级设定一定要注意,如果任务优先级不高,则应该设置成后台任务优先级,避免和UI线程抢占系统资源。
文章来源于互联网:HandlerThread原理分析、实战、最佳实践!
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/17196,转载请注明出处。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/17196,转载请注明出处。
评论0