美文共赏

Android消息机制

2021-01-25  本文已影响0人  liberty_7658

一个线程只有一个Looper 一个Looper只有一个MessageQueue
在创建Handler的时候必须先调用Looper.prepare()方法。

可以看到在创建Handler的时候需要获取Looper 当Looper为空的时候 会报错。

public Handler(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方法:
Looper.java

这里为什么要用到ThreadLocal类呢,这是因为ThreadLocal可以实现线程数据的隔离性(线程里面的数据保持自己的独立性,只有线程本身才可以持有他)

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

我们再看下Looper的创建过程:

 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));
    }
 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

Handler创建完成后就需要调用Looper.loop()方法实现消息的实时监听。
这个Looper.loop是一个死循环,流程是先获取Looper里面对应的MessageQueue。然后不断遍历当有消息的时候就获取Message里面对应的handler调用dispatchMessage将消息回调到需要使用的地方。

当我们的Message被回调出去后,这个message不会被销毁,只会被重置,目的是为了降低内存抖动,提升app性能,原因是:我们每次去创建Message,每次创建一个对象都会造成内存的开销,为了减少内存的开销,我们就要尽可能的去复用之前创建过的对象,所以在message里面就维护了一个spool,我们每次创建完成一个message就会把他里面的数据全部复位,然后添加到spool这哥队列里面去。想使用这个spool里面的东西我们可以使用handler.obtainMessage()

上一篇下一篇

猜你喜欢

热点阅读