Handler源码解析:自我学习

一、概述

    到现在为止handler的用处还是有点。毕竟是经常拿来面试的,作为一个基本技能是肯定要了解到它与事件分发机制一样基本都会被问到。以前都是看别人大神的源码解析,跟着其他大神的脚步自己也理解一下handler内部实现来作为自己的记录。

二、入口Handler

    handler都知道这几个关键词:Looper,Message,MessageQueue。入口必然是new Handler方法进入此方法。首先要知道它在android.os包下,然后看它构造方法看一眼最后调用的是2个参数的构造方法:

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

当然还有3个参数的构造方法:

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

只有这两个方法是真正做了初始化的其他都是调用这两个方法的其中之一。重点看2个参数的 一般初始化的也是这个。此时会看到一个熟悉的字眼就是内存泄漏的问题。也知道这样一句话:java中,非静态内部类会隐性地持有外部类的引用。

初始化了四个东西: mLooper = looper; mQueue = looper.mQueue;  mCallback = callback;mAsynchronous = async。mLooper 和mQueue很明显就是知道是什么了 而mAsynchronous百度一下就知道是异步的意思,mCallback呢?

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

这就关联了这几个重要的参数,接下来就是handler.sendMessage()方法了。

 public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

调用同一个方法sendMessageDelayed()方法。此方法:

 public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

调用sendMessageAtTime() 方法其实handler几乎都最后调用这个方法

其中常见的handler.post()接收runnable参数也可以看到其方法

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

其中的getpostMessage(r)可以看下:

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

runnbale赋值给message.callback了还是一个message对象。最后还是调用sendMessageAtTime()方法。暂且记住message.callback是runnable

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

单看最后发现是messageQueue最后执行enqueueMessage()方法但是先看msg.target= this,this是handler对象。可以得出结论。new handler()时关联Looper、MessageQueue。sendMessage()是调用MessageQueue来发送事件。

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

看到这里就需要了解Message 对象了

三、Message

        我们知道handler.sendmessage必然传递吗message对象。message通过message.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();
    }

看出就是new Message对象,其中的spoolSync这些参数

/*package*/ Runnable callback;
    
    // sometimes we store linked lists of these things
    /*package*/ Message next;

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

    private static final int MAX_POOL_SIZE = 50;

其实没有必要过于纠结(具体我也不清楚)。肯定一点是比直接new message要好,当然obtain()方法还有其他重载的方法。

其他就是一些可以常用的属性了

 public int what;
 public int arg1; 
 public int arg2;
 public Object obj;
Handler target;

在handler.sendMessage调用enqueueMessage时msg.target= this,也能看出一二了。这很重要!

到目前为止了解了 new handler 复写其回调方法handleMessage方法时(即callback方法)时关联了looper对象,通过looper.mQueue关联了MessageQueue对象。在message.obtain方法即使在属性上赋值。通过handler.sendMessage()方法把message.target即handler赋值了。接下来是关联两者即handler初始化就关联的两个MessageQueue和looper。

四、MessageQueue

     先贴代码:
 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
其实这很清楚了 其他的不用看就是一些赋值判断,主要还是for无限循环部分。一看第一步就蒙蔽了p.next是什么。算了再回到message里看哈:
//sometimes we store linked lists of these things
message next
相信英文不好的我都能看懂,不用纠结里面代码根据前人的智慧告诉我们这里是message的队列。就是将 message放入队列中。

五、looper

     到目前为止逻辑基本上就是handler.sendmessage就是将message放入message队列中,队列是无限循环的。现在看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));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
或许你知道有或许你不知道。在非主线程中需要先写 Looper.prepare,最后写Looper.loop来实现handler.handleMessage方法 。为什么主线程不写待会再说。可以看到prepare方法中 调用sThreadLocal.set()将new Looper传入。
static final ThreadLocal sThreadLocal = new ThreadLocal();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
目测是一个管理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();
        }
    }
又看到一个无线循环。但是这个无限循环是msg.target.dispatchMessage(msg),而msg.target是handler对象,前面重点介绍。
回到handler:

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是runnable对象执行run方法莫不是handler.post(r)方法的执行。还有一个mCallback.handleMessage(msg)这个方法也执行相信知道是handler的回调方法。还有handler的对象方法handleMessage。

六、最后一个问题

    在我们写new handler时并没有写关于looper的方法呀,不也没报错吗。这时有必要看下主线程的源码即activityThread。

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
java的main方法在activityThread里面,同时可以看到 loop.prepareMainLooper()获取looper对象并执行loop方法,所以不用自己手写,但是在非主线程中就必须要写不然会报错。

六、总结

   new handler 复写其回调方法handleMessage方法时(即callback方法)时关联了looper对象,通过looper.mQueue关联了MessageQueue对象。在message.obtain方法即使在属性上赋值。通过handler.sendMessage()方法把message.target即handler赋值了,并且将message加入消息队列中。在looper.loop方法中获取message并通过handler.dispatchMessage处理message对象。






你可能感兴趣的:(Handler源码解析:自我学习)