handler机制 android,Android Handler机制

Android开发中经常用到handler来发送消息,比如将消息抛到主线程去更新UI。handler机制涉及到四个核心的类:

Looper:消息循环,有一个Messagequenue,不断从消息队列中取出消息;

MessageQuenue:消息队列,里边包含Message;

Message:消息,里边有一个Handler,负责处理该消息;

Handler:管理消息队列,里边有Looper和MessageQueue;

为了更好的理解这三者的关系,我们可以想象成现实生活中,工厂里边的一条流水线。有一个放产品(Message)的传送带(MessageQuenue),被机器带动起来不断循环运行(Looper),而工人(Handler)需要将产品放到传送带上,然后传送到指定位置时再将产品进行下一步处理。

9ba9d8b694c1ef2235429b59ab3a7338.png

从上述表达的关系可以看出,有一个MessageQuenue,可以往里边仍Message,而Looper则要让MessageQuenue转起来,不断从里边取消息;而Handler负责把Message放到队列里边,最后再处理这个消息。

注:以下源码基于Android 9.0(版本名称:  Pie     API Level:  28)。

Looper类分析

frameworks/base/core/java/android/os/Looper.java

在该文件中给我们提供了一个实例:

*

 
 

*  class LooperThread extends Thread {

*      public Handler mHandler;

*

*      public void run() {

*          // ①调用prepare

*          Looper.prepare();

*

*          mHandler = new Handler() {

*              public void handleMessage(Message msg) {

*                  // process incoming messages here

*              }

*          };

*          // ② 进入消息循环

*          Looper.loop();

*      }

*  }

上述使用了Looper的两个关键调用(①和②),下面逐一分析。

Looper准备:

public static void prepare() {

prepare(true);

}

private static void prepare(boolean quitAllowed) {

// 一个Looper只能调用一次prepare

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

// 构造一个Looper对象,设置到调用线程的局部变量中

sThreadLocal.set(new Looper(quitAllowed));

}

// sThreadLocal定义

static final ThreadLocal sThreadLocal = new ThreadLocal();

ThreadLocal是一个泛型,是Java线程中的局部变量。全名是Thread Local Variable。具体可以自行研究源码:libcore/ojluni/src/main/java/java/lang/ThreadLocal.java

Looper构造函数:

private Looper(boolean quitAllowed) {

// 构造一个消息队列

mQueue = new MessageQueue(quitAllowed);

// 获取当前线程的Thread对象

mThread = Thread.currentThread();

}

prepare主要创建了Looper对象,并保存在调用线程的ThreadLocal中。同时Looper对象内部封装了一个消息队列。prepare通过ThreadLocal机制将Looper和调用线程关联。Looper循环:

/**

* Run the message queue in this thread. Be sure to call

* {@link #quit()} to end the loop.

*/

public static void loop() {

// 返回保存在调用线程的TLV中的Looper对象。

final Looper me = myLooper();

if (me == null) {

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

// 取出Looper的消息队列

final MessageQueue queue = me.mQueue;

// ... 细节省略

for (; ; ) {

// 从消息队列中取出消息

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

// ... 细节省略

try {

// 调用该消息的Handler,交给它的dispatchMessage函数处理

msg.target.dispatchMessage(msg);

dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;

} finally {

if (traceTag != 0) {

Trace.traceEnd(traceTag);

}

}

// ... 细节省略

msg.recycleUnchecked();

}

}

/**

* Return the Looper object associated with the current thread.  Returns

* null if the calling thread is not associated with a Looper.

*

*/

public static @Nullable

Looper myLooper() {

return sThreadLocal.get();

}

通过上面源码分析可以了解到Looper的作用:

封装一个消息队列(Messagequenue);

Looper的prepare函数将Looper和调用prepare的线程(即处理线程)绑定;

loop函数启动一个无线循环来处理消息队列中的消息。

当事件源向这个Looper发送消息的时候,其实是把消息加到这个Looper的消息队列里了。那么,该消息就将由和Looper绑定的处理线程来处理。可事件源又是怎么向Looper消息队列添加消息的呢?下面需要了解Looper、Message、Handler的关系。

Looper中有一个Message队列,里边存储的是一个个待处理的Message;

Message中有一个Handler,这个Handler是用来处理Message的。

其中Handler类封装了很多琐碎的工作。具体:

frameworks/base/core/java/android/os/Handler.java

final Looper mLooper; // 有一个Looper

final MessageQueue mQueue; // 有一个消息队列

final Callback mCallback; // 有一个回调用的类

final boolean mAsynchronous; // 异步相关设置,本文不做分析

Handler有几个构造函数,主要区别是对上面三个重要成员变量初始化上。

// 构造函数1

public Handler() {

this(null, false);

}

// 构造函数2

public Handler(Callback callback) {

this(callback, false);

}

// 构造函数3

public Handler(Looper looper) {

this(looper, null, false);

}

// 构造函数4

public Handler(Looper looper, Callback callback) {

this(looper, callback, false);

}

// 构造函数5

public Handler(boolean async) {

this(null, async);

}

public Handler(Callback callback, boolean async) {

// ... 细节省略

// 获得调用线程的Looper

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread " + Thread.currentThread()

+ " that has not called Looper.prepare()");

}

// 得到Looper的消息队列

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

public Handler(Looper looper, Callback callback, boolean async) {

mLooper = looper;

mQueue = looper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

上述构造函数中,Handler中的消息队列变量最终都会指向Looper的消息队列,Handler提供了一系列函数,帮助我们完成创建消息和插入消息队列的工作。这里列出一部分分析:

// 查看消息队列中是否有消息码是what的消息

public final boolean hasMessages(int what)

// 从Handler中创建一个消息码是what的消息

public final Message obtainMessage(int what)

// 从消息队列中移除消息码是what的消息

public final void removeMessages(int what)

// 发送一个只填充了消息码的消息

public final boolean sendEmptyMessage(int what)

// 发送一个消息,该消息添加到队列尾

public final boolean sendMessage(Message msg)

// 发送一个消息,该消息添加到队列头,所以优先级很高

public final boolean sendMessageAtFrontOfQueue(Message msg)

以sendMessage为了,其代码实现如下所示:

public final boolean sendMessage(Message msg)

{

return sendMessageDelayed(msg, 0);

}

public final boolean sendMessageDelayed(Message msg, long delayMillis)

{

if (delayMillis < 0) {

delayMillis = 0;

}

return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {

MessageQueue queue = mQueue;

if (queue == null) {

RuntimeException e = new RuntimeException(

this + " sendMessageAtTime() called with no mQueue");

Log.w("Looper", e.getMessage(), e);

return false;

}

return enqueueMessage(queue, msg, uptimeMillis);

}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

// 把Message的target设为自己,然后加入到消息队列

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}

Handler的消息处理

刚才,我们往Looper的消息队列中加入了一个消息,按照Looper的处理规则,它在获取消息后会调用target的dispatchMessage函数,再把这个消息派发给Handler处理。

public void dispatchMessage(Message msg) {

// 如果Message本身有callback,则直接交给Message的callback处理

if (msg.callback != null) {

handleCallback(msg);

} else {

// 如果本Handler设置mCallback,则交给mCallback处理

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

// 最后才交给子类处理

handleMessage(msg);

}

}

通常情况下,我们一般都是采用第三种方法,即在子类中通过重载handleMessage来完成处理工作。

要理解Handler机制,主要是弄清楚Looper、MessageQuenue、Message、Handler之间的关系。为了便于理解,我们可以把这套框架想象成现实生活中工厂流水线,工人(Handler)拿到产品(Message),放在传送带(MessageQuenue)上,同时做了一个标记(msg.target = this;),传送带由机器带动(Looper),然后当机器将产品传递到另一位置时,该员工根据产品上的标记,负责处理该产品,分发到不同的地方。

扩展:

Looper类里边启动了一个for(;;)循环,如果消息队列时会不会一直占用CPU时间片?

循环中queue.next()函数里边用到了pipe/epoll机制,确保不会占用CPU时间片。之后会通过源码进行分析。

标签:机制,public,Handler,Looper,msg,Message,Android,消息

来源: https://blog.csdn.net/yj_android_develop/article/details/112131393

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值