Android下Handler分析

介绍

Handler是Android应用内通讯组件,可实现线程间的通讯如子线程获取网络数据须在主线程更新UI使用,Handler通讯由

现在虽然不流行这样的方式但是我们还是需要了解其内部的原理

组件介绍

  • Handler(消息发送接收)
  • Message(消息体)
  • MessageQueue(消息队列)
  • Looper(轮询器)

Handler

  private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                //what可以理解为消息类型
                case 1:
                    Object obj = msg.obj;
                    Log.e("MainActivity", "handleMessage: " + obj);
                    break;
                default:
                    Log.e("MainActivity", "handleMessage: default message");
                    break;
            }
        }
    };

这里声明了一个持有主线程Looper的Handler对象我们可以在handlerMessage函数中对接收到消息进行相应的处理

		Message message = handler.obtainMessage();
        message.what = 1;
        message.obj = "this is Handler Message body";
        handler.sendMessage(message);

这里我们发送了一条消息,将会被handlerMessage中接收并且处理,值得注意的是获得Message对象我们应该使用obtainMessage()函数获取这样可以节省内存,为什么可以节省内存了我们继续往下看

我们来看一下obtainMessage的源码就知道啦

  @NonNull
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

   public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
    }

    public static Message obtain() {
        synchronized (sPoolSync) {
        //sPool 不等于null的话就会复用sPool
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        //直接新建了一个Message对象
        return new Message();
    }

在上述代码片段中我们可以看到obtainMessage最终执行了obtain函数,如果sPool不等于null的情况下就会复用sPool这个Message对象,所以这就是为什么推荐使用obtainMessage获取Message对象的原因了

Message

Message就是消息内容啦,可以理解为生活中你在某宝买了东西卖家给你寄过来的包裹

MessageQueue

MessageQueue就是消息池啦,我们调用sendMessage(),sendEmptyMessageDelayed(),sendEmptyMessageAtTime()这些函数其实就是把Message对象存放到Handler对应的MessageQueue中

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

这里其实就是把消息放进了消息池,那么就有小伙伴在线这个MessageQueue是哪来的呢?
那我们看下Looper这个东东就知道啦

Looper

Looper是个什么东东呢? 首先我们看下官方的解释

Class used to run a message loop for a thread. Threads by default do
not have a message loop associated with them; to create one, call
{@link #prepare} in the thread that is to run the loop, and then
{@link #loop} to have it process messages until the loop is stopped.

大概的意思是这是一个运行线程消息循环的类,默认和创建这个线程进行关联

final MessageQueue mQueue;

看下源码发现mQueue是它的一个成员变量并且用final修饰了,那么我们直接去构造函数找mQueue的初始化了

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

这里可以看到是直接new了一个MessageQueue对象仔细一看构造居然是private修饰的那这个对象是在哪里创建的呢

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

这里就是创建Looper对象的地方啦,那为什么我们之前使用handler发送消息的时候没有调用prepare()函数也没报异常呢,这是因为我们刚才创建的Handler使用的是MainThread的Looper所以我们不需要自己调用一遍prepare()了.

哈哈哈,讲了半天没讲到重点消息发送我知道到MessageQueue那消息是怎么让handlerMessage()处理的呢?

  public static void loop() {
   	  ...
      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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();
        }
    }

这里有个for死循环一直从消息池中取消息

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

在往下看我们有这么一行代码msg.target.dispatchMessage(msg)
其实这个target就是发送消息的handler,所以我们再看下handler的dispatchMessage()函数拿到这个msg都干了些啥

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

这里最终就把消息调到了handleMessage()就是我们处理消息这里

我们上面说到MainThread不需要我们去调用Looper.loop()来启动这个轮询,但是子线程中的Handler我们就需要调用下面两个函数来使这个Handler正常运作起来

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

看到这个函数的最后一行这里创建了一个对应线程的Looper对象,需要注意的是这个函数只能调用一遍否则将会抛出异常 “Only one Looper may be created per thread”

接下来就是调用Looper.loop()了,至此子线程中的Handler也能正常使用了.

你可能感兴趣的:(Android)