• MessageQueue和Looper学习


    MessageQueue和Looper的设计很巧妙,但是代码看上去很繁琐,我们不必了解其实现细节,知道其思路即可,这里我们探讨其基本原理,

    调用Handler的post等方法后,会调用到MessageQueue的enqueueMessage来按照执行时间顺序来排列,最好理解的取队列数据的实现方案是,while执行循环,不断的取队列头部的数据,但显然不能这样做。

    而Looper中使用epoll_wait来进行阻塞,在队列头部放入数据后,进行wake操作,通知Looper可以检查了,于是epoll_wait退出阻塞,判断队列头部数据的时间是否<=当前时间,符合的活,取出来,执行里面的操作处理。然后对新的队列头部数据进行同样的操作。

    不符合,计算时间差,作为继续要等待的时间,传给epoll_wait,等到了时间,自动解除阻塞,进行下一步判断处理。

    在处理的时候,只需要关注队列头部的数据的唤醒时间。

    就是这样清楚。

    关键就在于,epoll_wait可以1进行阻塞,2收到信号实时解除阻塞,3到达设定时间后解除阻塞

    int epoll_waitint epfdstruct epoll_event * events int maxeventsint timeout;

    boolean enqueueMessage(Message msg, long when) {

            if (msg.target == null) {

                throw new IllegalArgumentException("Message must have a target.");

            }

            synchronized (this) {

                if (msg.isInUse()) {

                    throw new IllegalStateException(msg + " This message is already in use.");

                }

                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;

    }

    Looper.java

    137    public static void loop() {

    138        final Looper me = myLooper();

    139        if (me == null) {

    140            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

    141        }

    142        final MessageQueue queue = me.mQueue;

    143

    144        // Make sure the identity of this thread is that of the local process,

    145        // and keep track of what that identity token actually is.

    146        Binder.clearCallingIdentity();

    147        final long ident = Binder.clearCallingIdentity();

    148

    149        // Allow overriding a threshold with a system prop. e.g.

    150        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'

    151        final int thresholdOverride =

    152                SystemProperties.getInt("log.looper."

    153                        + Process.myUid() + "."

    154                        + Thread.currentThread().getName()

    155                        + ".slow", 0);

    156

    157        boolean slowDeliveryDetected = false;

    158

    159        for (;;) {

    160            Message msg = queue.next(); // might block

    161            if (msg == null) {

    162                // No message indicates that the message queue is quitting.

    163                return;

    164            }

    165

    166            // This must be in a local variable, in case a UI event sets the logger

    167            final Printer logging = me.mLogging;

    168            if (logging != null) {

    169                logging.println(">>>>> Dispatching to " + msg.target + " " +

    170                        msg.callback + ": " + msg.what);

    171            }

    172

    173            final long traceTag = me.mTraceTag;

    174            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

    175            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;

    176            if (thresholdOverride > 0) {

    177                slowDispatchThresholdMs = thresholdOverride;

    178                slowDeliveryThresholdMs = thresholdOverride;

    179            }

    180            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);

    181            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

    182

    183            final boolean needStartTime = logSlowDelivery || logSlowDispatch;

    184            final boolean needEndTime = logSlowDispatch;

    185

    186            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {

    187                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));

    188            }

    189

    190            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;

    191            final long dispatchEnd;

    192            try {

    193                msg.target.dispatchMessage(msg);

    194                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;

    195            } finally {

    196                if (traceTag != 0) {

    197                    Trace.traceEnd(traceTag);

    198                }

    199            }

  • 相关阅读:
    Nginx HTTP框架综述
    打破行业界限,实现共赢的商业模式
    瞬态抑制二极管TVS的核心参数?|深圳比创达电子EMC(下)
    LeetCode·583.两个字符串的删除操作·动态规划
    J. Counting Trees (树,卡特兰数)
    零基础非计算机专业转行软件测试可行吗?
    stm32---外部中断
    云计算面试题【后期】
    CCF CSP题解:坐标变换(其二)(202309-2)
    南大通用GBase8s 常用SQL语句(289)
  • 原文地址:https://blog.csdn.net/aaajj/article/details/127590954