Handler机制剖析

前言

说起Handler我们再熟悉不过了,Handler用来进行线程间进行通讯的,但是Handler线程间通讯的机制以及原理是什么样的?下面我们就一起来剖析一下。

问题

(1)一个线程可以有几个Handler,可以有几个Looper?
答:一个线程只有一个Looper,可以有多个Handler。
(2)子线程中能否创建子线程的Handler?
答:可以。但是有个前提,在子线程创建Handler,必须先要创建子线程的Looper,可以看Handler的构造函数的源码:

public Handler() {
        this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> 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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这里的Looper.myLooper是先看当前Handler有无对应的Looper,如果没有Looper那么就会抛出异常:Can’t create handler inside thread…that has not called Looper.prepare();
所以,在子线程中创建Handler的前提是先创建对应的Looper,如果没有创建Looper就直接创建Handler,那么就会报异常。
调用了Looper.prepare()就创建了我们的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));
    }

我们看下这个ThreadLocal是什么?

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

看来,我们在prepare方法中创建Looper之后,并把Looper封装到了ThreadLocal中,我们看一下ThreadLocal类中是怎么存储Looper对象的:

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

首先通过Thread.currentThread()获取到当前的线程,然后,通过当前线程获取当前线程的ThreadLocalMap变量:

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
}

我们看Thread类的源码就可以看到,每一个Thread类都有一个ThreadLocalMap类型的变量:

ThreadLocal.ThreadLocalMap threadLocals = null;

而这里需要注意的一点是这个ThreadLocalMap类是ThreadLocal的一个内部类。
一会咱们再详细介绍ThreadLocalMap这个类,这里咱们先知道,通过Looper.prepare方法,是创建了Looper实例,然后把这个实例存储到了当前线程的的ThreadLocalMap变量中。

Looper中获取Looper实例的方法:

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

所以在子线程中,创建Handler之前,需要先通过Looper.prepare()创建Looper的实例。
在创建完了Handler对象之后,还需要通过Looper.looper()开始轮询,检查MessageQueue中有无消息,如果有消息,就交给Handler来处理消息。所以,在子线程中创建Handler大概是这个样子的:

public class MyThread extends Thread {
    private Handler handler;
    @Override
    public void run() {
        super.run();
        // 创建Looper对象并关联到Thread
        Looper.prepare();
        handler = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                return false;
            }
        });
        Looper.loop();
    }
}

这里我们需要注意一下,在创建Looper的时候,会调用Looper的构造函数:

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

我们发现是在Looper的构造函数中创建了MessageQueue。

回顾上面,这个是在子线程中创建Handler,需要调用Looper.prepare和Looper.looper。
那么在主线程中创建Handler的话,需要调用Looper.prepare和Looper.looper。
首先我们需要了解主线程是在什么时候创建的,每个App在启动的时候,都会创建一个进程,同时也会创建一个主线程或者称为UI线程,即我们常提到的ActivityThread。我们一起看一下ActivityThread这个类的main方法:

public static void main(String[] args) {
        .....

        Looper.prepareMainLooper();

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

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

我们发现,这里调用了Looper.prepareMainLooper();方法和Looper.loop()方法。
Looper.loop方法我们已经提到过了,下面我们看一下Looper.prepareMainLooper()这个方法:

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.prepareMainLooper方法其实也是调用了Looper.prepare方法,而且我们注意到,这个Looper只能有一个,如果当前线程已经有Looper对象,再创建新的Looper对象就会抛出异常。
所以我们可以判定,不管是在主线程还是子线程,创建Handler对象之前都必须先创建Looper对象,主线程和子线程唯一的不同是,主线程已经在ActivityThread的main方法中为我们提前创建好了Looper对象,并且通过Looper.looper方法开启了轮询。所以我们在主线程中可以直接创建Handler对象。而在子线程中却需要我们提前手动创建Looper对象,并且需要手动通过Looper.loop开启轮询。

下面我们来看一下ThreadLocal中的get方法:

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

通过当前线程,获取到Thread中的ThreadLocalMap变量,注意这个ThreadLocalMap类,这个类是ThreadLocal的静态内部类,类似于HashMap,是以this(即当前的ThreadLocal对象)为键,创建的Looper对象为值存储的:

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
}

Entry继承WeakReference,包括两个元素,一个ThreadLocal类型的成员和一个Object类型的成员value。其中ThreadLocal类型的成员是一个弱引用,其特点是,当引用元素无强引用时,JVM GC时会立即回收引用元素。
Entry对象Key为弱引用,当Key所指对象无强引用时,JVM GC时会自动回收该对象,从而造成Entry状态变为STALE,即无效状态。此时,必须对该Entry对象及其Value引用进行擦除,防止内存泄漏。

下面我们一起来看一下Handler的发送消息:

handler.postAtTime();
handler.postDelayed()
handler.sendMessage();
handler.sendMessageDelayed();
handler.sendEmptyMessage()
handler.sendMessageAtTime()

.........

handler发送消息有好多方法,但是这些方法,最终都调用了同一个方法,那就是:

public boolean sendMessageAtTime(@NonNull 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);
    }

这里调用了enqueueMessage方法:

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在enqueueMessage中有一行代码格外重要:

msg.target = this;

通过这行代码,message和Handler做了关联。
最终调用了MessageQueue的enqueueMessage方法:

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

在这里开启了对MessageQueue消息的轮询,这里是消息的入列,根据when,时间先后顺序,时间越早,越先进入消息队列。
这里需要注意的一点:调用了msg.recycle();

public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
 }
 void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

最终调用到了recycleUnchecked方法上,这样做是把消息的属性置空。
上面说的消息入列,下面看一下,消息的出列,消息的出列是通过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;

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

            .....
            try {
                msg.target.dispatchMessage(msg);
                .....
            } catch (Exception exception) {
                .....
            } finally {
                .....
            }
            .....
            msg.recycleUnchecked();
        }
    }

由于代码太长,我们只看关键代码,这里通过Looper获取到Looper对应的MessageQueue对象,然后通过一个for循环,调用queue.next()方法不断地从消息队列中拿到Message,拿到之后,就通过msg.target.diapatchMessage(msg);分发消息。这里的msg.target就是我们之前赋值的Handler的对象。dispatchMessage方法:

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

关于Handler的回调:
如果调用了

handler.post(new Runnable() {
         @Override
         public void run() {
                        
         }
})

我们看一下Handler的post方法:

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

实际上是通过getPostMessage方法,封装成了一个Message对象,把这个Runnable实例,赋值给了Message的callback对象:

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

然后会在Handler的dispatchMessage的回调方法中来进行判断:

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

如果callback设置了,那么就会指向handleCallBack方法:

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

这里相当于执行了,这里的run方法:

handler.post(new Runnable() {
         @Override
         public void run() {
                        
         }
})

如果没有设置那么我们就会走:

public void handleMessage(@NonNull Message msg) {
}

handler = new Handler(Looper.myLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                return false;
            }
});

你可能感兴趣的:(总结知识点)