当前位置: 代码迷 >> 综合 >> 【温故而知新】Android 消息机制/HandlerThread、Looper、Handler 在Java层的知识点
  详细解决方案

【温故而知新】Android 消息机制/HandlerThread、Looper、Handler 在Java层的知识点

热度:30   发布时间:2024-01-09 23:20:15.0

消息机制中的主要类

Android 消息机制的实现主要类有Looper、HandlerThread、Handler、Message、MessageQueue,但在使用过程中我们会发现Hander与Message提供的方法非常之多,Looper与MessageQueue等类提供的接口确很少,另外Android还提供了一个HandlerThread这个开箱即用的类(HandlerThread = Thread + Looper 模型的默认实现)来尽可能的方便我们使用消息机制。其实我们去看MessageQueue类的源码会发现它的方法是很多的,但都是defualt的访问权限,这意味着很多功能不是对外开放的,只能同包名下的类Handder、Looer这类访可以访问到。即尽可能的屏蔽内部的实际细节。**TIPS: 类跟类的方法默认是包访问权限,这点我们在日常开发也是会经常使用到的技巧,可以隐藏模块内部的实现细节。**还有在功能与职责的分配上更多的偏向或集中在Handler这个类的上,如提供产生消息并入消息队例的方法,还有提供处理消息内容的时机。HandlerThread仅仅就是帮忙起了个线程,创建并绑定Looer、MessageQueue对象,然后执行loop。剩下的交给Handler来表演了,即HandlerThread就是个搭台的,主角是咱Handler了呀
所以整个消息机制的主要类,可以分内外两个模块
在这里插入图片描述

说明:Looper归类为外部接口是因为,我们不想使用HnadlerThread这个现成的模板类时,可以使用Thread + Looper来实现一个绑定当前线程的消息队列而跑着一段loop的代码的线程实例!

可以直接看官网的Java Doc,在Javc Doc上类的私入方法(包括包访问权限的接口)是不会显示的。如 MessageQueue
在这里插入图片描述
我们再看下Hander类,从类的使用说明就看出是主角的了
在这里插入图片描述

实现层面

几个类的关系

在这里插入图片描述

如上图所示:
1、一个HandlerThread或Thread有且只有一个Looper实例,一个线程只有一个Looper实例,Looper实例会负责创建MessageQueue实例,即一个线程有且只有一个Looer跟一个MessageQueue,是一对一的关系;
2、Handler对象是不会创建任何的Looper、MessageQueue实例的,Handler对象在初始化时只能关联到某个线程的Looper实例,即它只是有某个线程的Looper、MessageQueue实例的引用,也是由于有它们的引用Handler才能往跟关联的线程发消息,同时在该线程的运行周期中处理消息。Handler实例跟线程实例是多对一的关系。
3、Handler实例是必须关联到某个线程的,它发的消息是发到关联线程的消息队列,处理消息也是在当前线程。Handler在发送消息时,把消息入消息队列时会把消息的target强制设置为自己(我认为是一个修订的操作),从而确保消息的发送者也是消息的处理者。这个修订的操作函数在讲Handler类时会提到
注:这里的线程是指HandlerThread的实例或用Thread但会在Thread实例的run方法创建Looper对象的线程实例

如下示例,是三个线程,每个线程都创建了对应的Handler,然后演示线程A发消息到线程B,线程B收到线程A的消息后给线程C发消息,线程C收到消息后给线程A发消息,形成一个消息接收与发送的闭环!(A>B>C>A)

package com.sdk.sdktestdemo;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.View;public class MainActivity extends AppCompatActivity {// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);this.findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {sendMessageTest(HANDLER_THREAD_A.getHandler(), "发给A的第一个消息");}});initHandlerThread();}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI();public static HandlerThreadEx HANDLER_THREAD_A;public static HandlerThreadEx HANDLER_THREAD_B;public static HandlerThreadEx HANDLER_THREAD_C;public static void initHandlerThread() {HANDLER_THREAD_A = new HandlerThreadEx("A");HANDLER_THREAD_A.setMessageHandler(new HandlerThreadEx.MessageHandler() {@Overridepublic void handler(Handler handler, Message msg) {/*** handler引用的Looper是那个线程的Looper,处理消息就是在那个线程* 所以这里是线程A*/handleMessageTest(msg);//                sendMessageTest(handler, "发给B的消息");/*** 这里是在线程A往线程B发消息,注意调用的是线程B的handler!* 如果是用这里的handler变量(是线程A的handler),那就是发给线程A自己了!*/sendMessageTest(HANDLER_THREAD_B.getHandler(), "发给B的消息");}});HANDLER_THREAD_A.start();HANDLER_THREAD_B = new HandlerThreadEx("B");HANDLER_THREAD_B.setMessageHandler(new HandlerThreadEx.MessageHandler() {@Overridepublic void handler(Handler handler, Message msg) {handleMessageTest(msg);sendMessageTest(HANDLER_THREAD_C.getHandler(), "发给C的消息");}});HANDLER_THREAD_B.start();HANDLER_THREAD_C = new HandlerThreadEx("C");HANDLER_THREAD_C.setMessageHandler(new HandlerThreadEx.MessageHandler() {@Overridepublic void handler(Handler handler, Message msg) {handleMessageTest(msg);sendMessageTest(HANDLER_THREAD_A.getHandler(), "发给A的消息");}});HANDLER_THREAD_C.start();}public static int S_MSG_ID = 0;public static void sendMessageTest(Handler handler, String msgInfo) {int msgId =  S_MSG_ID++;Message message = Message.obtain();message.what = msgId;message.obj = msgInfo;handler.sendMessageDelayed(message, 5 * 1000L);Log.d("HandlerTest", String.format("thread:%s >>> 发消息, msgId:%d, info:%s", Thread.currentThread().getName(), msgId, msgInfo));}public static void handleMessageTest(Message msg) {Log.d("HandlerTest", String.format("thread:%s <<< 收消息, msgId:%d, info:%s", Thread.currentThread().getName(), msg.what, msg.obj));}
}class HandlerThreadEx extends HandlerThread {private Handler mHandler;private MessageHandler mMessageHandler;public HandlerThreadEx(String name) {super(name);}public HandlerThreadEx(String name, int priority) {super(name, priority);}@Overrideprotected void onLooperPrepared() {super.onLooperPrepared();Log.d("HandlerTest", String.format("onLooperPrepared, thread:%s", Thread.currentThread().getName()));mHandler = new Handler(getLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {if (mMessageHandler != null) {mMessageHandler.handler(this, msg);}}};}public Handler getHandler() {return mHandler;}public void setMessageHandler(MessageHandler mMessageHandler) {this.mMessageHandler = mMessageHandler;}public interface MessageHandler {void handler(Handler handler, Message msg);}
}

运行效果如下

2021-12-10 19:18:19.262 12657-12657/com.sdk.sdktestdemo D/HandlerTest: thread:main >>> 发消息, msgId:0, info:发给A的第一个消息
2021-12-10 19:18:24.268 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 收消息, msgId:0, info:发给A的第一个消息
2021-12-10 19:18:24.268 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:1, info:发给B的消息
2021-12-10 19:18:29.274 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B <<< 收消息, msgId:1, info:发给B的消息
2021-12-10 19:18:29.274 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B >>> 发消息, msgId:2, info:发给C的消息
2021-12-10 19:18:34.280 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C <<< 收消息, msgId:2, info:发给C的消息
2021-12-10 19:18:34.281 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C >>> 发消息, msgId:3, info:发给A的消息
2021-12-10 19:18:39.287 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 收消息, msgId:3, info:发给A的消息
2021-12-10 19:18:39.288 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:4, info:发给B的消息
2021-12-10 19:18:44.294 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B <<< 收消息, msgId:4, info:发给B的消息
2021-12-10 19:18:44.295 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B >>> 发消息, msgId:5, info:发给C的消息
2021-12-10 19:18:49.300 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C <<< 收消息, msgId:5, info:发给C的消息
2021-12-10 19:18:49.301 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C >>> 发消息, msgId:6, info:发给A的消息
2021-12-10 19:18:54.307 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 收消息, msgId:6, info:发给A的消息
2021-12-10 19:18:54.308 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:7, info:发给B的消息
2021-12-10 19:18:59.313 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B <<< 收消息, msgId:7, info:发给B的消息
2021-12-10 19:18:59.313 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B >>> 发消息, msgId:8, info:发给C的消息
2021-12-10 19:19:04.319 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C <<< 收消息, msgId:8, info:发给C的消息
2021-12-10 19:19:04.320 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C >>> 发消息, msgId:9, info:发给A的消息
2021-12-10 19:19:09.325 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 收消息, msgId:9, info:发给A的消息
2021-12-10 19:19:09.325 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:10, info:发给B的消息
2021-12-10 19:19:14.331 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B <<< 收消息, msgId:10, info:发给B的消息
2021-12-10 19:19:14.332 12657-12725/com.sdk.sdktestdemo D/HandlerTest: thread:B >>> 发消息, msgId:11, info:发给C的消息
2021-12-10 19:19:19.338 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C <<< 收消息, msgId:11, info:发给C的消息
2021-12-10 19:19:19.339 12657-12726/com.sdk.sdktestdemo D/HandlerTest: thread:C >>> 发消息, msgId:12, info:发给A的消息
2021-12-10 19:19:24.344 12657-12724/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 收消息, msgId:12, info:发给A的消息

HandlerThread

关键点:HandlerThread继承了Thread,然后在run方法创建了Looper实例,即实现了Looper类的标准使用。避免我们直接使用Thread要写那些标准流程的调用代码。
在这里插入图片描述
还有一点是当我们使用/继承HandlerThread时可以在子类中Override onLooperPrepared方法来实例扩展的逻辑,比如我上面示例中我就在里边创建线程对应的一个Handler实例

// HandlerThread的run方法public void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared(); Looper.loop();mTid = -1;}/*** Call back method that can be explicitly overridden if needed to execute some* setup before Looper loops.*/protected void onLooperPrepared() {}

有个点大家需要注意,在HandlerThread的源码中我们可以看到该类中有一个mHandler成员,还有相关获取该值的方法,但实际上该方法是hide的API,所以我们是调不到该方法的!

public class HandlerThread extends Thread {int mPriority;int mTid = -1;Looper mLooper;private @Nullable Handler mHandler;public HandlerThread(String name) {super(name);mPriority = Process.THREAD_PRIORITY_DEFAULT;}
.......// 源码看得到这个接口,但实际上是hide的API,我们是调不到的/*** @return a shared {@link Handler} associated with this thread* @hide*/@NonNullpublic Handler getThreadHandler() {if (mHandler == null) {mHandler = new Handler(getLooper());}return mHandler;}

Looper

关键点:Looper负责创建一个消息队列实例,因为每个线程创建Looper后是保存在ThreadLocal变量中的,所以确保了一个线程只有一个Looper,也就确保了一个线程只有一个消息队列实例。即一线程一Lopper一队列的铁三角组合
核心的代码如下(Looper类的类方法prepare),还有一个技巧点是Looper类的构造方法是private的,这是一种简单的Builder模式了。以后我们想做到每个线程有自己的某个单例对象,可以参考这种实现方式

    public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}

Message

Message在生产者消费者模型中是产品的角色,产品生产出来后要被“消费”,在Andorid消息机制这里为方便我们管理与维护消息的“消费“就在Message类加了相关的回调和处理消息的处理者的绑定。即Message除了是常规数据载体还有相关的逻辑,这里逻辑是指消息中消息队列取出来后可用执行什么样的逻辑或消息该由谁再去分析和最终的消费。
如下图所示,示图了Message是由数据 跟 逻辑所组成的
在这里插入图片描述

消息在被Looper实例从消息队列取出来后,是把消息的处理交给消息绑定的Hander处理,在Looper.java类的loop方法的关键代码如下

   try {msg.target.dispatchMessage(msg); //这里是关键if (observer != null) {observer.messageDispatched(token, msg);}dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} catch (Exception exception) {

再去看下Handler类的dispatchMessage方法的代码

    /*** Handle system messages here.*/public void dispatchMessage(@NonNull Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

如上代码所示,Message最终是被Handler处理,如果Message有设置了callback(Runnable实例),执行Runnable的run方法。否侧由Handler处理消息,如果Handler有设置callback,由callback的实例处理消息,否侧由Handler的handleMessage方法处理消息。
还有一点之前有提到Message被那个Handler发送时,就由那个Handler去处理的关键逻辑是在Handler的enqueueMessage方法中的msg.target的赋值

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {msg.target = this; //这里是关键msg.workSourceUid = ThreadLocalWorkSource.getUid();if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

所以我们创建Message实例时绑定的Handler(target)其实意义不是很大的样子,另外Message的sendToTarget方法也有点坑人(尽管注释说明要注意空指针的情况)再加Message被sender到某个线程的消息列表时会被修正target为实际的Handler,所以构建Message时绑定Handler实例的操作不提供

    /*** Sends this Message to the Handler specified by {@link #getTarget}.* Throws a null pointer exception if this field has not been set.*/public void sendToTarget() {target.sendMessage(this);}

如下示例就是创建Message时设置的target是某个线程的handler,但实际发送出去的是另一个线程的Handler,消息的最终处理也是由发送了去的handler处理,当然是在handler绑定的线程处理了

package com.sdk.sdktestdemo;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.View;public class MainActivity extends AppCompatActivity {// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);this.findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {sendMessageTest(HANDLER_THREAD_A.getHandler(), "发给A的第一个消息");}});initHandlerThread();}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI();public static HandlerThreadEx HANDLER_THREAD_A;public static HandlerThreadEx HANDLER_THREAD_B;public static HandlerThreadEx HANDLER_THREAD_C;public static void initHandlerThread() {HANDLER_THREAD_A = new HandlerThreadEx("A");HANDLER_THREAD_A.setMessageHandler(new HandlerThreadEx.MessageHandler() {@Overridepublic void handler(Handler handler, Message msg) {// 这里是handler处理其绑定的消息Log.d("HandlerTest", String.format("%s", "这里是HANDLER_THREAD_A的handler在处理消息"));handleMessageTest(msg);sendMessageTest(handler, HANDLER_THREAD_B.getHandler(), "测试消息的内容");}});HANDLER_THREAD_A.start();HANDLER_THREAD_B = new HandlerThreadEx("B");HANDLER_THREAD_B.setMessageHandler(new HandlerThreadEx.MessageHandler() {@Overridepublic void handler(Handler handler, Message msg) {Log.d("HandlerTest", String.format("%s", "这里是HANDLER_THREAD_B的handler在处理消息"));handleMessageTest(msg);}});HANDLER_THREAD_B.start();}public static int S_MSG_ID = 0;public static void sendMessageTest(Handler handler, String msgInfo) {int msgId =  S_MSG_ID++;Message message = Message.obtain();message.what = msgId;message.obj = msgInfo;handler.sendMessageDelayed(message, 5 * 1000L);Log.d("HandlerTest", String.format("thread:%s >>> 发消息, msgId:%d, info:%s", Thread.currentThread().getName(), msgId, msgInfo));}public static void sendMessageTest(Handler sender, Handler target, String msgInfo) {int msgId =  S_MSG_ID++;Message message = Message.obtain();message.what = msgId;message.obj = msgInfo;//设置target为线程B的handlermessage.setTarget(target);//但实际发送还是由线程A的handler,所以还是会在线程A处理该消息sender.sendMessageDelayed(message, 5 * 1000L);Log.d("HandlerTest", String.format("thread:%s >>> 发消息, msgId:%d, info:%s", Thread.currentThread().getName(), msgId, msgInfo));}public static void handleMessageTest(Message msg) {Log.d("HandlerTest", String.format("thread:%s <<< 处理消息, msgId:%d, info:%s", Thread.currentThread().getName(), msg.what, msg.obj));}
}class HandlerThreadEx extends HandlerThread {private Handler mHandler;private MessageHandler mMessageHandler;public HandlerThreadEx(String name) {super(name);}public HandlerThreadEx(String name, int priority) {super(name, priority);}@Overrideprotected void onLooperPrepared() {super.onLooperPrepared();Log.d("HandlerTest", String.format("onLooperPrepared, thread:%s", Thread.currentThread().getName()));mHandler = new Handler(getLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {if (mMessageHandler != null) {mMessageHandler.handler(this, msg);}}};}public Handler getHandler() {return mHandler;}public void setMessageHandler(MessageHandler mMessageHandler) {this.mMessageHandler = mMessageHandler;}public interface MessageHandler {void handler(Handler handler, Message msg);}
}

运行日志输出

2021-12-15 19:27:45.968 14125-14125/com.sdk.sdktestdemo D/HandlerTest: thread:main >>> 发消息, msgId:0, info:发给A的第一个消息
2021-12-15 19:27:50.973 14125-14172/com.sdk.sdktestdemo D/HandlerTest: 这里是HANDLER_THREAD_A的handler在处理消息
2021-12-15 19:27:50.974 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 处理消息, msgId:0, info:发给A的第一个消息
2021-12-15 19:27:50.974 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:1, info:测试消息的内容
2021-12-15 19:27:55.977 14125-14172/com.sdk.sdktestdemo D/HandlerTest: 这里是HANDLER_THREAD_A的handler在处理消息
2021-12-15 19:27:55.977 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 处理消息, msgId:1, info:测试消息的内容
2021-12-15 19:27:55.977 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:2, info:测试消息的内容
2021-12-15 19:28:00.978 14125-14172/com.sdk.sdktestdemo D/HandlerTest: 这里是HANDLER_THREAD_A的handler在处理消息
2021-12-15 19:28:00.978 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 处理消息, msgId:2, info:测试消息的内容
2021-12-15 19:28:00.978 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:3, info:测试消息的内容
2021-12-15 19:28:05.980 14125-14172/com.sdk.sdktestdemo D/HandlerTest: 这里是HANDLER_THREAD_A的handler在处理消息
2021-12-15 19:28:05.981 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 处理消息, msgId:3, info:测试消息的内容
2021-12-15 19:28:05.981 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:4, info:测试消息的内容
2021-12-15 19:28:10.981 14125-14172/com.sdk.sdktestdemo D/HandlerTest: 这里是HANDLER_THREAD_A的handler在处理消息
2021-12-15 19:28:10.981 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A <<< 处理消息, msgId:4, info:测试消息的内容
2021-12-15 19:28:10.981 14125-14172/com.sdk.sdktestdemo D/HandlerTest: thread:A >>> 发消息, msgId:5, info:测试消息的内容

Handler

关键点:Handler需要绑定某个线程的Looper,这样它能得将消息发送到该线程的消息队列,并能在该线程中处理刚才发送的消息

MessageQueue

关键点:MessageQueue是整个消息机制的底层基石,也是涉及到最重点、最难理解的知识点

参考文档

  • Looper探底
  • Android 消息机制(Handler + MessageQueue + Looper)
  • 牛啊!居然把Handler事件分发、Handler线程切换讲得这么清楚
  • Android 源码分析 —— Handler、Looper 和 MessageQueue
  • 理解Java中的ThreadLocal
  • 你知道android的MessageQueue.IdleHandler吗?
  相关解决方案