Android消息处理探秘


下图为Android消息处理机制顺序图:


由图可知,第一步通过调用Looper.prepare()来创建Looper和MessageQueue java对象,MessageQueue java类通过保存单向链表头mMessages来遍历所有消息,注意此单向链表按时间顺序从早到晚排列,因此mMessages指向的消息总是为需最早处理的消息。在第5步创建C++ Looper对象,在其中创建读写管道并通过epoll来监控读管道。

第7步创建Handler给用户使用,第8步在消息处理线程内调用Looper.loop()来进入消息处理循环,在10步取下一消息时调用nativePollOnce方法,直到13步调到Looper.pollOnce(),在这里将等待管道POLLIN事件一定时间(timeoutMillis毫秒),如果有事件则返回否则等待timeoutMillis毫秒。在第10步MessageQueue.next()取下一消息时,将无限循环直到得到消息。循环时第一次传的超时时间timeoutMillis=0,如果此时尚无消息,则检查是否有IdleHandler,如有则调用所有Handler并置Handler为空,timeoutMillis设为0进行第二次查询, 以后timeoutMillis将设为-1,因此线程将一直挂起,直到有消息到来。

public class MessageQueue{
    final Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0; //第一次立刻返回不等待

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(mPtr, nextPollTimeoutMillis); //第一次=0

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                final Message msg = mMessages;
                if (msg != null) {
                    final long when = msg.when;
                    if (now >= when) { //如果消息发送时间满足
                        mBlocked = false;
                        mMessages = msg.next;
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;     //取消息成功
                    } else {
                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); //如果有消息但消息尚未到达发送时间,则以该时间到当前时间的时间差作为下次查询超时的时间
                    }
                } else {
                    nextPollTimeoutMillis = -1;      //无限等待
                }

                // If first time, then get the number of idlers to run.
                if (pendingIdleHandlerCount < 0) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount == 0) { //如果尚未设置IdleHandler
                    // 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("MessageQueue", "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;
        }
    }


第17步用户线程通过Handler发送消息,在20步将调用nativeWake来唤醒消息处理线程。最终第24步消息被处理。


    final boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        final boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) { //如果消息队列为空或者当前消息为发送时间最早的消息
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked; // mBlocked=true表示线程已被挂起
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                needWake = false; // still waiting on head, no need to wake up
            }
        }
        if (needWake) {
            nativeWake(mPtr);        //唤醒线程
        }
        return true;
    }


MessageQueue java类单向链表:

public final class Message implements Parcelable {
    Message next; //消息链表头


典型的消息处理代码

  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();      //创建Looper对象,在Looper对象创建时将创建MessageQueue.最后将Looper对象存储在线程局部变量中
  *
  *          mHandler = new Handler() { //创建Handler对象,在此将读取线程局部变量得到本线程的Looper对象及消息队列
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop(); //进入Looper对象的消息处理循环
  *      }
  *  }


用户主要操作接口类Handler,可以通过重载handleMessage()方法实现自定义方法处理:


Handler.java

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) { //如果消息已设置callback,则调用该callback函数
            handleCallback(msg);
        } else {
            if (mCallback != null) { //如果Handler已设置callback,则调用该callback处理消息
                if (mCallback.handleMessage(msg)) { //如果消息被处理
                    return;
                }
            }
            handleMessage(msg); //默认为空函数,用户可重载处理自定义消息
        }
    }
    private final void handleCallback(Message message) {
        message.callback.run();
    }
    public Handler(Callback callback) {
        mLooper = Looper.myLooper(); //得到本线程的Looper对象
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
    }

用户主要操作接口类Looper

frameworks/base/core/java/android/os/Looper.java

public class Looper{
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

    /**
     * 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();
        setMainLooper(myLooper());
        myLooper().mQueue.mQuitAllowed = false;
    }

    public static void loop() {
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        MessageQueue queue = me.mQueue;
                
        while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }

                long wallStart = 0;
                long threadStart = 0;

                msg.target.dispatchMessage(msg); //处理消息
                }                
                msg.recycle();
            }
        }
    }

问题:

1.为了实现消息队列等待机制,采用epoll方式来实现来消息时消息队列处理线程的唤醒和当无消息时线程挂起。实际上如果采用java对象wait/notify来实现此种功能更为简单,难道还有别的因素导致Google采用目前的设计?

分析:估计与IdleHandler有关,目前当消息队列首次为空或取完所有消息后,如果注册了IdleHandler则会调用这些Handler处理,然后才会无限等待下一个消息到来

2.跨进程消息传送如何实现:如鼠标键盘事件传递



ref:

Android应用程序消息处理机制

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值