简析Handler、MessageQueue、Looper

1.前言


         在android中,网络、文件等耗时操作在执行时,不可避免的造成线程操作阻塞,这就很尴尬了,毕竟点击,UI绘制都是再主线程中执行的,若是主线程阻塞掉,不可避免的造成用户体验下降,甚至会出现anr。所以异步操作在app中是不可少的,然而,android中做出了UI操作必须放置在UI线程也就是主线程中的限制,导致子线程并不能对视图界面进行及时的更新,怎么办呢,这就需要一个可以进行线程间通信的方法出现,Handler Looper MessageQueue应运而生。


2.从Looper开始       


       Hander-Looper机制的起始都是从一句Looper.prepare()开始的,哪怕是mainThread。所以,可以从prepare()入手:

public static void prepare() {
        prepare(true);
    }
</pre>继续往下看:<p></p><p></p><pre name="code" class="java" style="font-size:14px;">    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));
    }
ThreadLocal用作对对应线程提供线程变量副本,可以发现,prepare()中创建了Looper对象!而if中的异常判断则会避免一个线程中多个Looper的出现。沿着方法往下看,就是new Looper(quiallowed);
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
可以看出,quiAllowed与正在讨论的Looper关系并不大,所以暂且不管,new Looper完成了Looper对应的MessageQueue构建,以及当前Thread引用的获取。preper()就此打住,接下来就是loop():
public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        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
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(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();
        }
    }
按照老方法,第一个先看的就是myLooper(),虽然看之前就从字面明白,获取的必然是当前线程对应的Looper副本......

    public static Looper myLooper() {
        return sThreadLocal.get();
    }
嗯,果不其然......
往下走就是判断是否存在Looper对象,这也是先调用Looper.loop()必然报错的原因

之后就是MessageQueue对象的获取,至于Binder.clearCallingIdentity()以及loop()方法中的相关内容暂且不用管,知道和进程间通信有关就行......

之后就是for(;;)循环,通过MessageQueue的next方法不停的获取下一个Message,在通过Message.target.dispatchMessage分发出去,提前预告,Message.target是一个Handler对象。Message.recycleUnchecked会在之后讲解。

到此为止,讲解了Looper在Handler-Looper机制中的主要功用,总结就是,线程对应的Looper对象拥有一个自己的MessageQueue,并且不断的通过自己的MessageQueue获取新的Message, 注释中有一句很醒目的话

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

这就很有意思了,若是取到的msg为空就代表messagequeue退出执行了,并且中断执行当前方法,然而,在我们mainThread中也没见Looper退出的情况啊(退出后,触摸事件都会废掉,你怕不怕)。下节讲述机智的MessageQueue。


3.MessageQueue分析

      代码中第一次提到MessageQueue还是在Looper初创时,从MessageQueue构造方法看起:

  MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
quitAllowed这参数看起来有点意思,从名字就可以知道,作用是判断是否可退,这就不奇怪了,若是mainThread中的MessageQueue在程序还在执行时退出了,后果不堪想象,所以肯定在mainThread中是不可退出的,Looper中的prepareMainLooper方法也默默地支持了这种说法:
   public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
记得之前prepare中说暂不讨论的参数么,就是这个判断是否可以推出MessageQueue的boolean。

本地方法nativeInit()暂不影响分析,等需要的时候在讲解

下一个讲解的方法就是在Looper中提到的那个next():

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 (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                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) {
                    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 (false) Log.v("MessageQueue", "Returning message: " + msg);
                        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("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;
        }
    }

首先到的是 方法中的long类型 ptr ,先做搁置,不予理会

剩下的两个int型参数 pendingIdleHandlerCount与nextPollTimeoutMillis,一个是指IdleHandler调用的数量(后边会讲),一个则是最近下次Message事件发生的时间。然后,就又是熟悉的for(;;)循环,Binder。flushPendingCommands()暂且不管,后续会有关于Binder的博文。之后就是一个nativePollonce(ptr,nextPollTimeoutMillis)方法,名字听起来有些古怪:轮询一次......输入值有ptr,以及最短下次事件发生时间,这就有意思了,观察来看可能与事件的发生有关。由于是native方法,所以就直接讲解功用吧,具体代码,后续会进行分析。就是这个方法会只能的阻塞线程,之前说过,app惧怕线程阻塞,然而这里的阻塞更接近于等待而不是持续占用系统资源,一旦有相关的时间发生,线程就会在等待的状态恢复,执行事件内容,而这样机制的实现则基于Linux的poll,后续会在native代码中讲解。

之后就简单了,代码上同步锁,做事件类型的判断,要注意的是

if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }
当IdleHandler没有要发生的事件时,则会返回到for(;;)最端,另外要说的就是,当所有的Message都执行完时,nativePollonce中的时间传入是-1,也就是说进入线程等待状态,直至有事件发生。

顺便提下MessageQueue中的IdleHandler接口,实现这个接口,则会在MessageQueue执行完所有的或者当前空闲时,执行IdleHander中的内容,具体用法请百度或谷歌,不再讲述。


这里可能有点跳跃,讲下Message是如何加入Message链的

MessageQueue enquequeMessage 上代码:

  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("MessageQueue", 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;
    }
可以看到前两个if的本质就是在判断加入的msg是否有目标handler以及是否处于在使用状态,当msg有目标handler且自身并没有处于使用状态,则会上同步锁,手心啊判断的就是Looper是否推出,之后对msg对应状态进行修改,并根据msg属性判断是否需要唤醒线程,这就和上边讲的 在nativepollonce方法中传入-1进行无限制等待对应起来了,当需要时,会通过nativeWake方法进行线程激活。

4.Handler

       Looper,MessageQueue,Handler相交会简单不少,闲话不说,从new Handler开始:
public Handler() {
        this(null, false);
    }
 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 that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

其中async是指消息是否同步,不影响分析不予理会

之后的if中则是判断当前Handler以及其继承类在被调用时存在的状态,三个isXXX对应的是,匿名类,成员变量以及局部变量(比如在方法中进行声明并new出来),改举动是为了方式出现内存泄漏

之后的mLooper,如果不是进行指定,则对应的是当前线程的Looper,也就是说若是当前线程Looper还没有被建立,则会抛出异常,new完之后则是开发最为关心的post了:

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
 public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
可见,无论是post还是postDelayed,其本质都是对应的sendMessageDelayed,只不过对延迟时间设置的不同而已,继续往下看:

  public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

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

嗯 ,这次找到正主了,无论如何花式的post或者send,最后都会在enqueueMessage方法中通过调用Looper对应的queue添加到Message链中,然后,进行数据处理,以及判断是否需要激活线程。

至于message分发就不再讲述了:

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
很简单的源码,这就是为什么我们使用可以通过父类的handleMessage方法获取Message的原因。


进阶部分

       这里只简单的分析下MessageQueue中重要的native方法(此处将使用5.1的源码)。

       nativeInit

       nativeInit 位于android_os_MessageQueue.cpp(android5.1\frameworks\base\core\jni)

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}
其中incStrong作用强引用计数,可忽略。可以看出在nativeInit中只是进行了底层 MessageQueue与 应用层MessageQueue的对应生命,两者之间并没有什么关系,但是,这个一jlong形式返回的对象则就是前面提到的mPtr,在唤醒或pollonce的时候,传入的mPtr,也会被转换为NativeMessageQueue.

       nativePollOnce

       nativePollonce 同样位于android_os_MessageQueue.cpp(android5.1\frameworks\base\core\jni)

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, timeoutMillis);
}
在nativePollOnce中,首先将前边提到mPtr转换为对应的NativeMessageQueue,然后调用方法pollOnce:

void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
    mInCallback = true;
    mLooper->pollOnce(timeoutMillis);
    mInCallback = false;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}
查看头文件,可发现mLooper,其实就是Looper的指针
然后,继续跟踪pollOnce()(/ frameworks / native / jb-dev / . / libs / utils / Looper.cpp)

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
        result = pollInner(timeoutMillis);
    }
}
虽然找到了代码,发现参数并不对应,这时候就应该去头文件看看,会有惊喜:
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
    inline int pollOnce(int timeoutMillis) {
        return pollOnce(timeoutMillis, NULL, NULL, NULL);
    }

这下就明白了,虽然调用的是pollOnce(int timeoutMillis)本质上则是还是之前的pollOnce(timeoutMillis,null,null,null);

再看下pollInner:

int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
    // Adjust the timeout based on when the next message is due.
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }
    // Poll.
    int result = ALOOPER_POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    // Acquire lock.
    mLock.lock();
    // Check for poll error.
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error, errno=%d", errno);
        result = ALOOPER_POLL_ERROR;
        goto Done;
    }
    // Check for poll timeout.
    if (eventCount == 0) {
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - timeout", this);
#endif
        result = ALOOPER_POLL_TIMEOUT;
        goto Done;
    }
    // Handle all events.
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeReadPipeFd) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;
    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
                ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
                        this, handler.get(), message.what);
#endif
                handler->handleMessage(message);
            } // release handler
            mLock.lock();
            mSendingMessage = false;
            result = ALOOPER_POLL_CALLBACK;
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }
    // Release lock.
    mLock.unlock();
    // Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == ALOOPER_POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                    this, response.request.callback.get(), fd, events, data);
#endif
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);
            }
            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = ALOOPER_POLL_CALLBACK;
        }
    }
    return result;
}
最为关键的一句代码就是:

eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
当timeoutMillis则会令线程处于等待状态,而且上可知,除了县城的等待与唤醒 Jlong对象之外,framework层关于MessageQueue looper的代码并没有与应用层中的数据有什么实质的交换,也就是说,Framework层的Looper机制与应用层对应相似,但是其主要任务就是对当前线程进行唤醒和等待。nativeWake就不予讲述了,有兴趣自行观看。 如果有时间,会讲解下epoll poll的使用与区别。

最后一点:android线程中,除了线程变量外,同一进程的变量在同进程不同的线程间是共享的,所以,所谓的android线程间通信,实质是线程的等待与唤醒







  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值