【Android 消息处理】Handler、Looper、Message 源码浅析

Android 消息处理机制核心的四个类是 Handler、Looper、Message 和 MessageQueue

Message

属性

Message 类的几个成员变量

//前面四个字段是 public 的,可以直接修改属性值,Bundle 对象需要使用 set 和 get 方法。
 public int what;    
 public int arg1;  
 public int arg2;
 public Object obj;
 Bundle data;

 long when;
 Handler target;
 Runnable callback;
 Message next;

 private static final Object sPoolSync = new Object();
 private static Message sPool;
 private static int sPoolSize = 0;

创建对象

创建一个 Message 对象可以通过无参的构造方法,但是推荐使用 Message 类提供的 static 的 obtain 方法。

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();
    }

因为 Message 内部维护了一个 Message 的对象池,上面提到的 sPoolSync 字段主要是同步用的,保证多线程安全,如果对象池不为空,那么栈顶的 Message 就被取出重用,指针指向下一个 Message 对象,队列长度减1。
如果对象 池为空,就 new 一个新的 Message 对象返回。
Message 有个 recycle 方法,每次 Looper 轮询完都会调用 Message 的该方法进行回收,该方法内部调用了 recycleUnchecked 方法,把 Message 的所有属性都还原,并入栈。
Message 还重载了很多带参数的 obtain 的方法,这些方法都先调用了无参的 obtain 方法获取一个 Message 对象,然后对属性进行赋值:

public static Message obtain(Message orig)
public static Message obtain(Handler h) 
public static Message obtain(Handler h, Runnable callback)//callback 字段没有提供 set 方法,只能在创建对象时传入,callback 并不是一个回调接口,而是一个 Runnable 对象
public static Message obtain(Handler h, int what)
public static Message obtain(Handler h, int what, Object obj)
public static Message obtain(Handler h, int what, int arg1, int arg2)
public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj)

我们平时发送 Message 都是通过 Handler 对象的相关方法,也可以调用 Message 自身的 sendToTarget 方法,当然前提是在创建 Message 时传入了 Handler 参数或者通过 setTarget 方法为 target 属性赋值,该内部也是调用了 Handler 的 sendMessage 方法:

public void sendToTarget() {
        target.sendMessage(this);
    }

Handler

Handler 也重载了构造方法,这些构造方法可以分为两类,一类是传入了 Looper 对象的,一类是没有传入 Looper 对象的。

public Handler()
public Handler(Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async) 

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

传入 Looper 对象的最后都调用了三个参数的构造方法,在构造方法中对 mLooper、mQueue、mCallback、mAsynchronous 成员变量进行了初始化,mCallback 可以为 null,mAsynchronous 默认为 false:

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

没有传入 Looper 对象的最后都调用了两个参数的构造方法,

 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

在该构造函数中通过 Looper.myLooper() 方法获取到一个 Looper 对象对 mLooper 属性进行赋值,也就是说在 Handler 的构造函数中必须绑定一个 Looper 对象,否则会抛异常。Looper.myLooper() 方法获得的是当前线程的 Looper 对象,也就是创建 Handler 的代码所在的线程,所以在使用没有传入 Looper 对象的构造函数构造 Handler 时,当前线程必须有一个 Looper 对象,在 UI 线程中已经创建了 Looper 对象,而在子线程中默认情况下是没有 Looper 对象的。如果通过构造函数传入 Looper 的话则可以是任意线程的 Looper。
Handler 内部也提供了创建了 Message 的构造方法,内部其实也是调用了 Message 的 obtain 方法,Message 对象的 target 属性就是该 Handle 对象:

public final Message obtainMessage()
public final Message obtainMessage(int what)
public final Message obtainMessage(int what, Object obj)
public final Message obtainMessage(int what, int arg1, int arg2)
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)

Handler 发送消息主要有 sendXXX 和 postXXX 两个系列,先来看 send 开头的方法:

public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)

sendEmptyMessageXXX 就是内部创建一个只有 what 属性的 Message 对象,这些方法最后都是调用了 sendMessageAtTime 方法:

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) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

方法内部就是将 Message 对象加入在构造函数中绑定的 MessageQueue,同时将自身赋值给 Message 的 target 字段,最终由这个 Handler 来处理该 Message。
post 开头的方法最终也是调用了 sendMessageAtTime 方法,不同之处是传入了一个 Runnable 对象

public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtFrontOfQueue(Runnable r)

postXXX 方法内部调用了 getPostMessage 方法创建了一个 Message 对象,传入的 Runnable 类型的参数就是赋值给这个 Message 对象的 callback 字段。所以使用 postXXX 方法时,在 Handler 所在的线程要执行代码直接写在 Runnable 的 run 方法里面,不需要在重写 Handler 的 handleMessage 方法。

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

Handler 在接收到 Messgae 后会调用 dispatchMessage 方法

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();
    }

可以看到,如果 Message 的 callback 属性不为 null,则执行 Message 的 callback 属性的 run 方法,也就是我们在创建 Message 对象时传入的 Runnable 参数或者 postXXX 方法中传入的 Runnable 参数;
如果 callback 为 null,则调用 Handler 的 mCallback 的 handleMessage 方法,这个 mCallback 也是创建 Handler 对象时传入的参数,只是这个 mCallback 不是 Runnable 对象,是一个Handler 内部声明的回调接口 Callback。
如果 mCallback 也为 null 的话,则调用 handleMessasge 方法,这个方法是在定义 Handler 时重写的方法。

Looper

前面说过,通过 Looper.myLooper 方法可以获得当前线程的 Looper 对象

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

这里的 ThreadLocal 成员变量使每一个线程保持一个各自独立的对象,为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
在非 UI 线程中并没有 Looper 对象,需要调用 prepare 方法,创建一个 Looper 对象,这样 myLooper 方法就是 null le。

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));
    }

可以看到 prepare 方法就是 new 了一个 Looper 对象然后存储到 ThreadLocal 中,每个线程只能创建一个 Looper 对象。

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

在 Looper 的构造方法里面就是创建了一个 MessageQueue 成员变量,然后将当前线程(Looper.prepare 方法执行的线程)赋值给 mThread 成员变量,把 Looper 和当前 Thread 绑定。
有了 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.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

在 loop 方法里面分别先获取当前线程(loop 方法执行的线程)的 Looper 对象,然后得到该 Looper 对象的 MessageQueue,从 MessageQueue 中取出队首的 Message,调用该 Message 目标 Handler 的 diapatchMesssage 方法进行消息处理,在消息处理完毕后对 Message 对象进行了回收。
Looper 也提供了获取主线程 Looper 的方法:

 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

MessageQueue

MessageQueue 主要的两个方法 enqueueMessage 和 next 分别在 Handler 和 Looper 中调用,这里不作讨论。

你可能感兴趣的:(【Android 消息处理】Handler、Looper、Message 源码浅析)