Thread、Handler和HandlerThread关系详解

前言

前几天看到一道面试题:Thread、Handler和HandlerThread有什么区别?,这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler、Message、Looper、MessageQueue),详见《 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)》

但是这个HandlerThread是拿来做什么的呢?它是Handler还是Thread?我们知道Handler是用来异步更新UI的,更详细的说是用来做线程间的通信的,更新UI时是子线程与UI主线程之间的通信。那么现在我们要是想子线程与子线程之间的通信要怎么做呢?当然说到底也是用Handler+Thread来完成(不推荐,需要自己操作Looper),Google官方很贴心的帮我们封装好了一个类,那就是刚才说到的:HandlerThread。(类似的封装对于多线程的场景还有AsyncTask)

使用方法

还是先来看看HandlerThread的使用方法:
首先新建HandlerThread并且执行start()

private HandlerThread mHandlerThread; ...... mHandlerThread = new HandlerThread("HandlerThread"); handlerThread.start();

创建Handler,使用mHandlerThread.getLooper()生成Looper:

final Handler handler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { System.out.println("收到消息"); } };

然后再新建一个子线程来发送消息:

new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000);//模拟耗时操作 handler.sendEmptyMessage(0); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();

最后一定不要忘了在onDestroy释放,避免内存泄漏:

@Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); }

执行结果很简单,就是在控制台打印字符串:收到消息

原理

整个的使用过程我们根本不用去关心Handler相关的东西,只需要发送消息,处理消息,Looper相关的东西交给它自己去处理,还是来看看源码它是怎么实现的,先看构造方法:

public class HandlerThread extends Thread {}

HandlerThread其实还是一个线程,它跟普通线程有什么不同?

public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } ...... }

答案是多了一个Looper,这个是子线程独有的Looper,用来做消息的取出和处理。继续看看HandlerThread这个线程的run方法:

protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper();//生成Looper notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared();//空方法,在Looper创建完成后调用,可以自己重写逻辑 Looper.loop();//死循环,不断从MessageQueue中取出消息并且交给Handler处理 mTid = -1; }

主要就是做了一些Looper的操作,如果我们自己使用Handler+Thread来实现的话也要进行这个操作,再来看看getLooper()方法:

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; }

方法很简单,就是加了个同步锁,如果已经创建了(isAlive()返回true)但是mLooper为空的话就继续等待,直到mLooper创建成功,最后看看quit方法,值得一提的是有两个:

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; }

quitSafely是针对在消息队列中还有消息或者是延迟发送的消息没有处理的情况,调用这个方法后都会被停止掉。

总结

HandlerThread的使用方法还是比较简单的,但是我们要明白一点的是:如果一个线程要处理消息,那么它必须拥有自己的Looper,并不是Handler在哪里创建,就可以在哪里处理消息的。

如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。

以上就是对Thread、Handler和HandlerThread关系 的资料整理,后续继续补充相关资料,谢谢大家对本站的支持!

时间: 2024-09-28 23:25:10

Thread、Handler和HandlerThread关系详解的相关文章

Thread、Handler和HandlerThread关系详解_Android

前言 前几天看到一道面试题:Thread.Handler和HandlerThread有什么区别?,这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler.Message.Looper.MessageQueue),详见< 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)> 但是这个HandlerThread是拿来做什么的呢?它是Handler还是Thread

MyBatis:一对多表关系详解:重复表id问题

MyBatis:一对多表关系详解(从案例中解析)

Android中屏幕密度和图片大小的关系详解

Android中屏幕密度和图片大小的关系详解 前言 Android中支持许多资源,包括图片(Bitmap),对应于bitmap的文件夹是drawable,除了drawable,还有drawable-ldpi.drawable-mdpi.drawable-hdpi.drawable-xhdpi.drawable-xxhdpi等,同一张图片放到上面不同的文件夹中是有区别的,比如一张100 * 100像素大小的图片,分别放在上述各个文件夹中,然后将其设置为ImageView(假设宽高都是wrap_co

android Handler机制之ThreadLocal详解

概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Message:Handler发送.接收和处理的消息对象 Looper:每个线程只能拥有一个Looper.它的looper()方法负责循环读取MessageQueue中的消息并将读取到的消息交给发送该消息的handler进行处理. MessageQueue:消息队列,它采用先进先出的方式来管理Message.

Handler详解系列(一)——Handler异步消息机制详解(附图)

MainActivity如下: package cc.cn; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.app.Activity; /** * Demo描述: * Android异步消息机制分析(附图) * * ===================

Handler与Android多线程详解_Android

下面是一段大家都比较熟悉的代码: 复制代码 代码如下: Handler handler = new Handler(); handler.post(myThread); //使用匿名内部类创建一个线程myThreadRunnable mythread = new Runnable() {public void run() {}}; 一开始,相信很多人都以为myThread中的run()方法会在一个新的线程中运行,但事实并非如此. 上述代码中的handler并没有调用线程myThread的star

Handler详解系列(五)——Handler的post()方法详解

MainActivity如下: package cc.testui1; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.app.Activity; /*

Handler与Android多线程详解

下面是一段大家都比较熟悉的代码:复制代码 代码如下:Handler handler = new Handler(); handler.post(myThread); //使用匿名内部类创建一个线程myThreadRunnable mythread = new Runnable() {public void run() {}}; 一开始,相信很多人都以为myThread中的run()方法会在一个新的线程中运行,但事实并非如此. 上述代码中的handler并没有调用线程myThread的start(

Android消息机制Handler的工作过程详解

综述 在Android系统中,出于对性能优化的考虑,对于Android的UI操作并不是线程安全的.也就是说若是有多个线程来操作UI组件,就会有可能导致线程安全问题.所以在Android中规定只能在UI线程中对UI进行操作.这个UI线程是在应用第一次启动时开启的,也称之为主线程(Main Thread),该线程专门用来操作UI组件,在这个UI线程中我们不能进行耗时操作,否则就会出现ANR(Application Not Responding)现象.如果我们在子线程中去操作UI,那么程序就回给我们抛