再一次看Handler源码的一些收获

Handler原理的大致描述

一、APP启动

在ActivityThread 类的main方法(这是APP启动入口方法),会有下面代码

ActivityThread.java

public static void main(String[] args) {
		//调用了prepare 方法 将当前线程与创建的Looper对象关联起来
        Looper.prepareMainLooper();  
		//...删除多余的部分
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
		//...删除多余的部分
        Looper.loop();
    }

Looper.java

 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));
 }
private Looper(boolean quitAllowed) {
     mQueue = new MessageQueue(quitAllowed);
     mThread = Thread.currentThread();
 }

上面的代码解释一下,就是创建了一个Looper对象(Looper构造方法中一共做了两件事,创建了MessageQueue和获取到当前线程实例),然后与当前线程也就是主线程绑定,开启了一个loop()循环。

ThreadLocal 就是一个保存线程数据的容器,任何位置只要在同一个线程中,获取到的Looper都是同一个。

二、创建Handler 发送消息

    private static class MyHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.d("Handler","Message msg.what = "+msg.what);
        }
    }
   new Thread(new Runnable() {
       @Override
       public void run() {
           MyHandler myHandler = new MyHandler();
           Message message = Message.obtain();
           message.what = 100;
           message.obj = " XXXxxxx";
           myHandler.sendMessage(message);
       }
   }).start();

通常我们使用Handler 是上面的这种方式,上面主要就做了一件事 sendMessage(message),这个方法主要完成了一个将 message消息添加到Message队列或者说Message消息池当中。

Handler.java

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

最终他会调用Handler类中的这个方法将 MessageQueue实例传递给enqueueMessage方法。

MessageQueue.java

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

		//核心部分的代码, 仔细理解发现他就只做了一件事,就是想消息串联起来,并且是按照when的大小从小打到排序
		// 怎么理解 就是
		// msg1.next = msg2    
		// msg2.next = msg3    
		// msg3.next = msg4 
		// msg4.next = mMessages = msg1
		 
        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循环,很重要, 上面的操作就是在这个 for循环完成的
            for (;;) {
                prev = p;
                p = p.next;
                // 当当前消息的when 小于上一个消息的when 
                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;
}

上面的代码比较难理解,我也是在 本子上比划了半天才勉强看懂一些,至于最后一步 msg4.next = mMessages = msg1这个结果是我计算出来的, 但是不太确定msg4.next = msg1 最后会这样联系起来。

简单概括sendMessage 就是完成了一个Message 加入到消息队列的一个操作,并且按照when从小到大的顺序

三、处理消息

回到第一步 Looper.loop()方法中开启了一个无线循环 不停的从消息队列中获取消息处理。

Looper.java

    public static void loop() {
        final Looper me = myLooper();

        final MessageQueue queue = me.mQueue;
		
        for (;;) {
        	//难点在 next中做了什么东西
            Message msg = queue.next(); // might block
            final long end;
            try {
                msg.target.dispatchMessage(msg);
            } 
        }
    }

上面的方法是删除了一些多余的方法之后的结果, 看上去非常好理解,就是queue.next() 获取一个对象,然后去msg.target.dispatchMessage(msg); 至于target是什么,以前博客中说道过就是Handler对象引用。 最后就是调用
第二步中的handleMessage(Message msg) 处理消息。

    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        //这里又有一个无限for循环
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
			//native 阻塞方法  nextPollTimeoutMillis = 0 表示不阻塞  
			// nextPollTimeoutMillis  = -1 表示阻塞
			// nextPollTimeoutMillis   > 0  表示延时
            // nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                //第二步中 说道过mMessages 最后是指向了 第一个msg1
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                	// 如果获取到的消息大于当前时间 nextPollTimeoutMillis  > 0 到时间以后就会唤醒执行
                	// 有一个问题 这个机制的前提就是保证 消息队列是已经按照when的大小排序好的
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

这个方法就是 取出一个消息 计算出nextPollTimeoutMillis 值 判断是否需要阻塞。 然后释放CPU 等待被唤醒。

发布了58 篇原创文章 · 获赞 16 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dingshuhong_/article/details/93378008