Android消息机制完全指南:Handler、Looper、MessageQueue源码解析

Android消息机制完全指南:Handler、Looper、MessageQueue源码解析

【免费下载链接】Android-Review 🔥Android 复习资料汇总(每周持续更新~) 【免费下载链接】Android-Review 项目地址: https://gitcode.com/gh_mirrors/an/Android-Review

Android消息机制是Android开发的核心基础,其中Handler、Looper和MessageQueue三者构成了线程间通信的基石。无论是UI更新、异步任务处理还是系统组件交互,都依赖于这套高效的消息循环系统。本指南将从基本概念到源码实现,全面解析Android消息机制的工作原理,帮助开发者深入理解其内部运作机制。

一、Android消息机制核心组件

Android消息机制主要由四个核心组件构成,它们协同工作实现了线程间的消息传递和处理:

1.1 Handler

Handler是消息机制的对外接口,主要负责发送消息和处理消息。它有两个核心用途:

  • 安排Message和Runnable在将来的某个时刻执行
  • 将需要在不同线程执行的操作排入队列,实现线程间通信

Handler创建时会绑定当前线程的Looper,如果线程没有Looper则会报错。主线程(ActivityThread)在创建时会自动初始化Looper,因此可以直接使用Handler,这也是为什么我们能在Activity中直接使用Handler的原因。

1.2 Message

Message是Handler接收和处理的消息对象,它包含了要传递的数据和处理信息。Message可以通过Message.obtain()方法获取,这种方式可以从对象池中复用Message,避免频繁创建对象带来的性能开销。

1.3 MessageQueue

MessageQueue是消息的队列,采用先进先出的原则。它的主要操作是插入(enqueueMessage)和读取(next)消息,读取操作会伴随着删除操作。MessageQueue内部通过单链表实现,而不是真正的队列结构。

next()方法是一个无限循环的阻塞方法,如果消息队列中没有消息,它会一直阻塞等待;当有新消息到来时,会返回这条消息并将其从链表中移除。

1.4 Looper

Looper是消息泵,负责不断从MessageQueue中取出消息,并将消息分发给对应的Handler处理。每个线程只能有一个Looper实例。

Looper提供了prepare()方法为当前线程创建Looper,loop()方法启动消息循环。主线程的Looper通过prepareMainLooper()方法创建,应用可以通过getMainLooper()方法获取主线程的Looper。

二、消息机制工作原理

2.1 ThreadLocal与Looper绑定

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,其他线程无法访问。Looper正是通过ThreadLocal实现与线程的绑定。

当调用Looper.prepare()时,会创建一个Looper实例并存储到ThreadLocal中:

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.myLooper()可以获取当前线程的Looper:

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

2.2 消息循环流程

Android消息机制的工作流程可以概括为以下几个步骤:

  1. 创建Looper:通过Looper.prepare()为线程创建Looper,同时会创建一个MessageQueue
  2. 创建Handler:Handler在构造时会获取当前线程的Looper和MessageQueue
  3. 发送消息:通过Handler的sendMessage()post()方法发送消息,最终会调用enqueueMessage()将消息加入MessageQueue
  4. 处理消息:Looper的loop()方法不断从MessageQueue中读取消息(通过next()方法),并调用msg.target.dispatchMessage(msg)将消息分发给对应的Handler处理
  5. 退出循环:调用Looper的quit()quitSafely()方法可以退出消息循环

三、核心组件源码解析

3.1 MessageQueue实现

MessageQueue主要包含enqueueMessage()next()两个核心方法:

enqueueMessage() - 插入消息到队列:

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        msg.markInUse();
        msg.when = when;
        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);
        }
    }
    return true;
}

next() - 从队列中读取消息:

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        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 {
                    // 获取消息并从队列中移除
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 没有消息,无限期等待
                nextPollTimeoutMillis = -1;
            }

            // 处理退出
            if (mQuitting) {
                dispose();
                return null;
            }

            // 首次循环时处理IdleHandler
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // 没有IdleHandler需要处理,阻塞等待
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // 运行IdleHandler
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // 释放引用

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // 重置IdleHandler计数,确保不会再次运行
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

3.2 Looper实现

Looper的核心是loop()方法,它实现了消息循环:

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // 确保此线程本地进程标识的身份
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // 可能会阻塞
        if (msg == null) {
            // 消息为null表示消息队列正在退出
            return;
        }

        // 日志相关代码省略...

        try {
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        // 日志和统计相关代码省略...

        msg.recycleUnchecked();
    }
}

loop()方法是一个无限循环,通过不断调用MessageQueue的next()方法获取消息。当next()返回null时,循环结束,Looper退出。

Looper提供了两种退出方法:

  • quit():直接退出Looper,会移除消息队列中所有消息
  • quitSafely():安全退出Looper,会处理完消息队列中已有的消息后再退出

3.3 Handler实现

Handler的主要工作是发送消息和处理消息。发送消息的方法最终都会调用enqueueMessage()

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

消息处理通过dispatchMessage()方法实现:

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

处理优先级为:

  1. 首先处理Message的callback(Runnable对象)
  2. 然后处理Handler的mCallback接口
  3. 最后调用Handler的handleMessage()方法

四、消息机制应用场景

4.1 线程间通信

Android规定UI操作必须在主线程进行,子线程不能直接操作UI。通过Handler可以实现子线程向主线程发送消息,从而更新UI:

// 主线程中创建Handler
private Handler mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在主线程处理消息,更新UI
        textView.setText("Received message: " + msg.obj);
    }
};

// 子线程中发送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        // 执行耗时操作
        String result = doHeavyWork();
        
        // 发送消息到主线程
        Message msg = Message.obtain();
        msg.obj = result;
        mHandler.sendMessage(msg);
    }
}).start();

4.2 延迟任务执行

通过Handler的postDelayed()方法可以实现延迟执行任务:

// 延迟2秒执行任务
mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        // 执行延迟任务
        doSomething();
    }
}, 2000);

4.3 HandlerThread使用

HandlerThread是一个包含Looper的线程类,它简化了在子线程中创建消息循环的过程:

// 创建HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();

// 获取HandlerThread的Looper创建Handler
Handler mHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在HandlerThread线程中处理消息
        processMessage(msg);
    }
};

// 发送消息
mHandler.sendMessage(Message.obtain());

// 退出时释放资源
handlerThread.quit();

4.4 IntentService实现

IntentService是一个基于HandlerThread的服务,用于执行后台任务,任务执行完成后会自动停止:

public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 在后台线程处理任务
        String action = intent.getAction();
        if ("com.example.ACTION_DO_TASK".equals(action)) {
            doBackgroundTask();
        }
    }
}

五、常见问题与优化

5.1 内存泄漏问题

Handler如果使用不当容易造成内存泄漏,主要原因是Handler持有Activity的引用,而Handler的生命周期可能比Activity长。解决方法:

  1. 使用静态内部类定义Handler,并使用WeakReference引用Activity
  2. 在Activity的onDestroy()方法中移除Handler的所有消息
private static class MyHandler extends Handler {
    private WeakReference<MainActivity> mActivityRef;
    
    public MyHandler(MainActivity activity) {
        mActivityRef = new WeakReference<>(activity);
    }
    
    @Override
    public void handleMessage(Message msg) {
        MainActivity activity = mActivityRef.get();
        if (activity != null) {
            // 处理消息
        }
    }
}

// 在Activity中
@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}

5.2 消息屏障与异步消息

Android消息机制支持消息屏障(SyncBarrier)和异步消息(Asynchronous Message),用于优先处理某些重要消息:

  • 消息屏障:通过postSyncBarrier()方法发送,它会阻塞普通消息,只允许异步消息通过
  • 异步消息:创建消息时调用setAsynchronous(true),可以绕过消息屏障优先处理

系统UI绘制相关的消息就是通过这种机制优先处理的。

5.3 消息优先级

MessageQueue中的消息是按时间戳(when)排序的,时间戳小的消息先被处理。可以通过以下方式设置消息的执行顺序:

  1. 使用sendMessageAtFrontOfQueue()将消息发送到队列头部
  2. 构造Message时指定更早的when时间戳

六、总结

Android消息机制是基于Handler、Looper、MessageQueue和Message四个核心组件构建的,它们协同工作实现了线程间的通信。理解消息机制的工作原理对于Android开发至关重要,不仅有助于解决多线程编程中的问题,还能帮助开发者写出更高效的代码。

通过本文的学习,我们了解了:

  • 消息机制的核心组件及其作用
  • 消息循环的工作流程
  • 核心组件的源码实现细节
  • 消息机制的常见应用场景
  • 如何避免消息机制使用中的常见问题

掌握Android消息机制,将为你的Android开发之路打下坚实的基础。更多关于Android消息机制的详细内容,可以参考项目中的Android知识点汇总.md文档。

【免费下载链接】Android-Review 🔥Android 复习资料汇总(每周持续更新~) 【免费下载链接】Android-Review 项目地址: https://gitcode.com/gh_mirrors/an/Android-Review

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值