Android系统中Thread,Looper,MessageQueue,Message,Handler相互关系的简单分析

本文深入解析Android中Handler机制的工作原理,包括Thread、Looper、MessageQueue和Message等核心组件之间的交互方式,以及Handler如何在主线程和自定义线程中处理消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先粗略说一下Thread,Looper,MessageQueue,Message,Handler之间的基本关系:
1.一个Thread实例中会包含一个Looper实例
2.一个Looper实例中会包含一个MessageQueue实例
3.Handler把Message推送到MessageQueue内
4.Looper实例在Thread中处于死循环运行状态,负责不断的从MessageQueue中取出消息,取出消息后交给Handler处理
小结:Looper是运行在Thread实例中的,Message又是由Looper取出来交给Handler处理的,所以Handler处理Message的地方也是运行在Thread实例中的。

这个Thread实例有可能是UI主线程,也有可能是自定义线程 :)


Android开发中Handler处理Message分两种情况:
1.Handler在应用主线程中处理Message
2.Handler在自建的线程中处理Message


对于第1种情况先按下不表,等分析完第2种情况后再回过头来看第1种情况会容易很多。
对于第2种情况,开发情景一般如下面例子的代码,先上全部代码:

// 自定义类ExampleThread继承自Thread,内部Handler成员internalHandler
class ExampleThread extends Thread {

    private static final String TAG = "ExampleThread";
    private static final int MSG_WORK = 1;
    private static final int MSG_PLAY_GAMES = 2;
    private Handler internalHandler;

    @Override
    public void run() {
        Looper.prepare();
        synchronized (ExampleThread.this) {
            internalHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case MSG_WORK:
                            Log.d(TAG, "I'm working");
                            break;
                        case MSG_PLAY_GAMES:
                            Log.d(TAG, "I'm playing games");
                            break;
                        default:
                            break;
                    }
                }
            };
            ExampleThread.this.notifyAll();
        }
        Looper.loop();
    }

    public void goWork() {
        while (internalHandler == null) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        internalHandler.sendEmptyMessage(MSG_WORK);
    }

    public void goPlayGames() {
        while (internalHandler == null) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        Message msg = Message.obtain(internalHandler, MSG_PLAY_GAMES);
        msg.sendToTarget();
    }
}

// 测试代码,goWork和goPlayGames方法的实现都是通过internalHandler发送Message,internalHandler是在exampleThread线程内部处理Message
public void test() {
    ExampleThread exampleThread = new ExampleThread();
    exampleThread.start();
    exampleThread.goWork();
    exampleThread.goPlayGames();
}

从ExampleThread.run中只看到了下面3步:
Looper.prepare();
internalHandler = new Handler()
Looper.loop();
难道只要这3步就把Handler处理Message的流程机制创建好了?


那我们只能一步步来分析了。

先看Looper.prepare();做了些是什么,上Looper的关键源码:

package android.os;
public final class Looper {
    private static final String TAG = "Looper";
    /*ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量*/
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    /*当所在线程为UI主线程时sMainLooper才会被使用到*/
    private static Looper sMainLooper;
    /*Looper持有的消息队列*/
    final MessageQueue mQueue;
    /*Looper所在线程的实例*/
    final Thread mThread;

    /*自定义线程调用此方法来prepare*/
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        /*如果sThreadLocal.get()不为null,则表示Looper已经prepare过了,不能重复prepare*/
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        /*调用Looper构造器创建一个Looper实例,并set进sThreadLocal。由于ThreadLocal的特性,在同一线程(当前线程)中我们通过sThreadLocal.get()得到的都是同一个Looper实例;而在不同线程中我们通过sThreadLocal.get()得到的又是不同的Looper实例。*/
        sThreadLocal.set(new Looper(quitAllowed));
    }

    private Looper(boolean quitAllowed) {
        /*创建一个消息队列*/
        mQueue = new MessageQueue(quitAllowed);
        /*获得当前线程的实例*/
        mThread = Thread.currentThread();
    }
	
    /*UI主线程调用此方法来prepare*/
    public static void prepareMainLooper() {
        /*也是通过调用prepare来创建Looper实例*/
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            /*跟自定义线程不同的是把创建的Loooper实例赋给了sMainLooper引用*/
            sMainLooper = myLooper();
        }
    }

    /*其他进程要跟UI主线程IPC的话可以通过此方法获得主线程的Looper,然后向主线程发送事件,比如按键事件等*/
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    /*Looper开始工作*/
    public static void loop() {
        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,可能会阻塞*/
            Message msg = queue.next();
            if (msg == null) {
                /*表示消息队列正在quitting*/
                return;
            }
            /*取出来的Message交给target(即Handler,为什么target是Handler等后面Message源码部分再说)去调度处理*/
            msg.target.dispatchMessage(msg);
            /*Message处理完后释放资源*/
            msg.recycleUnchecked();
        }
    }

    /*prepare时把创建的Looper实例set进了sThreadLocal,所以在同一线程中myLooper方法得到的肯定是同一个Looper实例,所以一个Thread实例只有一个Looper实例*/
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /*在Looper的构造器中创建了MessageQueue,由myLooper()性质决定了同一线程中myQueue方法得到的肯定也是同一个MessageQueue实例*/
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

    /*判断是否在当前线程中。比如在线程A的代码中aLooper = myLooper()来获得线程A的Looper实例aLooper,然后可能在任何代码地方通过aLooper.isCurrentThread()来判断所在代码是否运行在线程A中*/
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }

    /*退出消息队列,当前消息队列中未被处理的消息将被丢弃。一旦调用quit后再向消息队列中推送消息就会失败,例如Handler.sendMessage(Message)会返回false*/
    public void quit() {
        mQueue.quit(false);
    }

    /*安全退出消息队列,当前消息队列中的消息都会被处理完。同样,一旦调用quit后再向消息队列中推送消息就会失败,例如Handler.sendMessage(Message)会返回false*/
    public void quitSafely() {
        mQueue.quit(true);
    }

    /*获得Looper实例中的当前线程实例*/
    public @NonNull Thread getThread() {
        return mThread;
    }

    /*获得Looper实例持有的消息队列,此方法为非静态方法,myQueue()为静态方法*/
    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }
}

通过Looper的源码可以明白,通过调用Looper.prepare(),已经在当前Thread中创建了一个唯一的Looper实例,并且Looper实例持有的MessageQueue实例也已经创建好了。在当前线程中任何地方调用myLooper()都可以得到唯一的Looper实例。


Looper.prepare()分析完后继续分析internalHandler = new Handler()做了什么工作。
先上Handler的关键源码:

package android.os;
public class Handler {

    private static final String TAG = "Handler";
    /*当前线程中的消息队列*/
	final MessageQueue mQueue;
    /*当前队列中的Looper*/
    final Looper mLooper;
    /*Handler的内部回调,Handler构造器中可以传入Callback,如果传入了此Callback,则Message将交给此Callback的handleMessage去处理,而不是交给Handler的handleMessage去处理*/
    final Callback mCallback;
    final boolean mAsynchronous;

	public interface Callback {
        public boolean handleMessage(Message msg);
    }
	
    /*Handler有很多构造器,无参构造器的话传入的Callback为null*/
    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }

    public Handler(boolean async) {
        this(null, async);
    }

    public Handler(Callback callback, boolean async) {
        /*获得当前线程中的Looper实例*/
        mLooper = Looper.myLooper();
        /*如果Looper实例为空,说明当前线程还没有调用Looper.prepare*/
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        /*获得当前线程中的消息队列*/
        mQueue = mLooper.mQueue;
        /*保存构造器传入的callback*/
        mCallback = callback;
        mAsynchronous = async;
    }

    /*向消息队列中推送一个Runnable,通过getPostMessage把Runnable封装成Message,调用sendMessageDelayed继续处理*/
    public final boolean post(Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
 
    /*Runnable封装成Message*/
	private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        /*Runnable实例成了Message的callback成员变量*/
        m.callback = r;
        return m;
    }

    /*向消息队列中推送一个Message,调用sendMessageDelayed继续处理*/
    public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }

    /*sendMessageDelayed调用sendMessageAtTime继续处理*/
    public final boolean sendMessageDelayed(Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    /*无论是向消息队列中推送Runnable还是Message,最后都走到了这个方法中*/
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        /*如果当前线程的消息队列为null,说明出了问题,推送会失败*/
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        /*把Message推送到消息队列中*/
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        /*把Message的target成员设置成了当前Handler。所以在Looper.loop()中的msg.target.dispatchMessage(msg);即调用了Handler的dispatchMessage*/
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        /*把Message压入队列*/
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    /*Looper.loop()中获得到待处理的Message后会调度到此处继续处理*/
    public void dispatchMessage(Message msg) {
        /*msg.callback在getPostMessage方法中赋值,msg.callback即为Runnable,如果Message成员中Runnable不为空则直接处理Runnable*/
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            /*mCallback在Handler构造器中赋值,如果有Callback就交给Callback来处理Message*/
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            /*最低优先级是由Handler的handleMessage来处理Message,子类一般会重载Handler的handleMessage*/
            handleMessage(msg);
        }
    }
	
    /*Message成员中Runnable的处理*/
	private static void handleCallback(Message message) {
        message.callback.run();
    }
	
    /*子类重载此方法来处理Message*/
    public void handleMessage(Message msg) {
    }
}

通过分析Handler的源码,在Handler的构造方法中获得了当前Thread中的Looper实例和Looper实例持有的MessageQueue实例。所以Handler已经和Looper,MessageQueue关联起来了,已经能够通过Handler向MessageQueue中推送消息了。

到目前为止就差处理MessageQueue中的Message了。也就差分析Looper.loop();了,这个loop方法在Looper的源码中已经写了详细的注释了。
所以仅需要在自定义线程中做完3步:
Looper.prepare();
internalHandler = new Handler()
Looper.loop();
就可以通过Handler往当前线程的MessageQueue中推送Message,然后当前线程中的Looper会从MessageQueue中依次取出Message来处理。


Handler在自定义线程中处理Message的情况分析完了,接着分析看看在UI主线程中Handler处理Message的机制是怎么搭建好的呢?
应用程序启动时会创建主线程,即ActivityThread,四大组件无论哪一个启动都是创建的ActivityThread。
上ActivityThread的main方法的源码:

public static void main(String[] args) {
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

跟自定义Thread中run方法内的差不多,Looper.prepare()换成了Looper.prepareMainLooper(),其实还是同一个Looper实例,只是多了一个Looper.getMainLooper()。new Handler换成了ActivityThread.getHandler()。

上ActivityThread.getHandler()的源码:
final Handler getHandler() {
    return mH;
}

final H mH = new H();
private class H extends Handler {}

所以UI主线程中的过程跟自定义线程是一样的。
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值