首页 > 其他分享 >【Android】Message、Handler、MessageQueue、Looper 详解

【Android】Message、Handler、MessageQueue、Looper 详解

时间:2023-03-19 17:14:37浏览次数:44  
标签:MessageQueue handler Handler 线程 Looper msg Message

1 前言

​ Handler 即处理器,常用于跨线程通讯:线程A 和线程 B 拥有同一个 handler 对象,在线程 A 中使用 handler 的 sendMessage() 方法发送消息,在线程 B 中使用 handler 的 handleMessage() 方法处理消息。

​ Handler 家族主要有:Message、Handler、MessageQueue、Looper。

(1)应用场景

  • 子线程处理完耗时操作后,请求主线程更新 UI
  • 线程 A 定时给线程 B 发送消息
  • 线程 A 周期性给线程 B 发送消息

(2)Handler 家族

  • Message:消息类,通过 obtain() 方法可以生成一个 message 对象,每个 message 对象必须有一个 handler 对象;
  • Handler:消息处理器,用于生成(obtainMessage)和处理消息(handleMessage);
  • MessageQueue:消息队列,用于存储消息,通过 enqueueMessage() 放入消息,next() 取出消息;
  • Looper:循环器,用于取出消息,并通知 handler 执行消息。

(3)Handler 机制基本原理

img

​ 假设在线程 A 中创建了 handler 对象,重写了 handler 的 handleMessage() 方法,并且将 handler 对象传给了线程 B,则线程 B 和线程 A 间的通讯如下:

  1. 生成消息:线程 B 通过 handler.obtainMessage() 生成消息(内部会调用 Message.abtain() 方法,并且会把当前 handler 传给 message 对象);
  2. 发送消息:线程 B 通过 handler.sendMessage() 发送消息,再调用 mQueue.enqueueMessage() 将消息放入消息队列;
  3. 取出消息:线程A 中 mLooper 对象的 loop() 方法一直循环执行(若 mQueue 中没数据会等待),其内部会调用 mQueue 对象的 next() 方法,取出一个消息 msg;
  4. 执行任务:线程 A 中取出的 msg 对象在创建时已绑定 handler,通过调用 msg.target.dispatchMessage() 方法,通知 handler 执行 handleMessage() 方法。

2 Handler 机制源码解析

2.1 Message

(1)类图

img

(2)生成消息

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

​ sPool 是可用的空消息对象池 ,其本质是链表,sPool 指向链表的头结点,next 指向下一个节点。

(3)处理消息

msg.target.dispatchMessage(msg)

//最终会执行如下一种
msg.callback.run()
handler.mCallback.handleMessage(msg)
handler.handleMessage(msg)

​ target 是 Message 绑定的 handler 对象。

2.2 Handler

(1)类图

img

(2)Looper 对象的获取

​ 若 handler 在主线程中创建,则不需要显式地给 handler 传递 Looper 对象。在主线程被创建时,系统会为主线程创建 Looper 对象,并开启消息循环。

public Handler() {
    this(null, false);
}

public Handler(Handler.Callback callback, boolean async) {
    ...
    mLooper = Looper.myLooper(); //获取与当前线程绑定的Looper对象
    ...
    mQueue = mLooper.mQueue;
    ...
}

​ 若 handler 在子线程中创建,则需要显示地传递 looper 对象,因为子线程在创建时不会创建 Looper 对象。

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Handler.Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    ...
}

(3)生成消息

public final Message obtainMessage() {
    return Message.obtain(this);
}

​ 将 this 赋值给 message.target,与 message 对象绑定。

(4)发送消息

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;
    ...
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

​ 从 enqueueMessage() 方法中可以看到,在消息入队之前,将 this 赋值给了 msg,确保每个 msg 都能绑定一个 handler

(5)发送任务

public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

​ 可以看到,即使发送的是 runnable,也会封装为 message。

(6)处理消息

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

public void handleMessage(Message msg) {
}

public interface Callback {
    public boolean handleMessage(Message msg);
}

​ 从 dispatchMessage() 方法中可以看到,处理消息的次序为:

  1. msg.callback.run()
  2. mCallback.handleMessage(msg)
  3. handleMessage(msg)

2.3 MessageQueue

(1)类图

img

(2)存储消息

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        ...
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) { //根据消息时间,查找待插入位置
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; //插入消息
            prev.next = msg;
        }
        if (needWake) {
            nativeWake(mPtr); //唤醒 looper
        }
    }
    return true;
}

​ mMessages 是消息队列的链头。

(3)取出消息

Message next() {
    ...
    int nextPollTimeoutMillis = 0;
    for (;;) {
        ...
        nativePollOnce(ptr, nextPollTimeoutMillis); //等待
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else { //取出消息
                    ...
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    ...
                    return msg;
                }
            } 
            ...
        }
        ...
    }
}

2.4 Looper

(1)类图

img

(2)创建 Looper 对象

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)); //创建Looper对象,并与当前线程绑定
}

(3)创建 MessageQueue

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

(4)循环

public static void loop() {
    final Looper me = myLooper();
    ...
    final MessageQueue queue = me.mQueue;
    ...
    for (;;) {
        Message msg = queue.next(); //可能会等待
        ...
        msg.target.dispatchMessage(msg); //处理消息
        ...
        msg.recycleUnchecked(); //回收消息
    }
}

3 应用

3.1 应用一

(1)主线程(处理消息)

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        System.out.println("打印消息");
    }
};

(2)子线程(发送消息)

handler.sendEmptyMessage(0x111);

3.2 应用二

(1)主线程(处理消息)

Handler handler = new Handler();

(2)子线程(发送消息)

handler.post(new Runnable() {
    @Override
    public void run() {
        System.out.println("打印消息");
    }
});

4 拓展

​ 第3节中的案例都是子线程给主线程发送消息,但是某些场景需要主线程给子线程发送消息,或2个子线程间发送消息。默认情况下,系统会为主线程创建 Looper 对象,并开启消息循环,但新建的子线程中不会创建 Looper 对象,此时,就需要应用到 HandlerThread 类。

(1)HandlerThread 类图

img

(2)HandlerThread 核心源码

// 消息循环,通过threadHandler.start()开启循环
public void run() {
    mTid = Process.myTid();
    Looper.prepare(); //创建looper对象,并与当前线程绑定
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop(); //消息循环
    mTid = -1;
}

//获取handler,并注入mLooper
public Handler getThreadHandler() {
    if (mHandler == null) {
        mHandler = new Handler(getLooper());
    }
    return mHandler;
}

(3)应用

​ 线程 A(处理消息)

HandlerThread handlerThread = new HandlerThread("A");
handlerThread.start();
//Handler handler = handlerThread.getThreadHandler();
Handler handler = new Handler(handlerThread.getLooper());

​ 线程 B(发送消息)

handler.post(new Runnable() {
    @Override
    public void run() {
        System.out.println("打印消息");
    }
});

​ 声明:本文转自【Android】Message、Handler、MessageQueue、Looper 详解

标签:MessageQueue,handler,Handler,线程,Looper,msg,Message
From: https://www.cnblogs.com/zhyan8/p/17233630.html

相关文章