首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

android的UI开发工程师向导

2012-06-27 
android的UI开发工程师指引不管是MFC,还是linux,还是android,UI开发都是如下两大核心机制:第一个是消息循

android的UI开发工程师指引

不管是MFC,还是linux,还是android,UI开发都是如下两大核心机制:

第一个是消息循环,第二个是界面组织结构。

围绕着这些,衍生出来的OpenGL,SurfaceView,SurfaceFinger等都是为这两大机制服务的。

?

打一个比方。

?

?

消息循环是UI中的发动机。

?

界面组织结构就是UI的设计结构。

?

而其他的东西,则是建立在这些基础之上的。

?

理解这两大块儿,那么android的UI基础就学得差不多了。这个时候可以结合一些例子,来做一些真正有意义的开发,例如UI特效啊。自定义动画啊。。。。也可以顺便把动画机制给理解吃透。

?

?

接下来就学一下Canvas,SurfaceFlinger,Matrix,来做一些特效。

如果想更深入地学习。那么学习一下OpenGL。

再想深入的话,学习一下JNI编程。

再深入的话,把java虚拟机给了解一下,也许对于提高程序效率帮助很大。

?

?

本篇就介绍一下消息队列:

?

android_os_MessageQueue.cpp

MessageQueue.java

Looper.cpp (frameworks\base\native\android)?2369?2011/12/12

Looper.java (frameworks\base\core\java\android\os)?8874?2011/12/12
Handler.java (frameworks\base\core\java\android\os)?23620?2011/12/12

Activity中的事件默认都是在UI线程中发生的。

这意味着Activity中的任何一个函数执行完之后,都要回到消息队列,这个节点。handleMessage结束之后,就会再次去消息队列查看消息。这跟windows上开发的消息队列的概念是一致的。

?

?

1.入队:

入队的时候,按照Message.when的大小进行排序。如果时间相同,那么按照入队的先后进行排序。

如果入队的时候,时间戳为0,那么就激活消息管道。否则不激活等超时。

?

MessageQueue.java

?

2.?遍历

遍历的时候,按照队列头部的时间戳(为0,则立即调用,否则等待超时),进行poll函数调用。

?

? final Message next() {
??????? int pendingIdleHandlerCount = -1; // -1 only during first iteration
??????? int nextPollTimeoutMillis = 0;

??????? for (;;) {
??????????? if (nextPollTimeoutMillis != 0) {
??????????????? Binder.flushPendingCommands();
??????????? }
??????????? nativePollOnce(mPtr, nextPollTimeoutMillis);

??????????? 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) {
??????????????????? // 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;
??????? }
??? }

?

?

?

3.。?下面看一下looper的loop函数

?

Looper.java (frameworks\base\core\java\android\os)?8874?2011/12/12

int Looper::pollInner(int timeoutMillis) {#if DEBUG_POLL_AND_WAKE    LOGD("%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        LOGD("%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;#ifdef LOOPER_STATISTICS    nsecs_t pollStartTime = systemTime(SYSTEM_TIME_MONOTONIC);#endif#ifdef LOOPER_USES_EPOLL    struct epoll_event eventItems[EPOLL_MAX_EVENTS];    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);#else    // Wait for wakeAndLock() waiters to run then set mPolling to true.    mLock.lock();    while (mWaiters != 0) {        mResume.wait(mLock);    }    mPolling = true;    mLock.unlock();    size_t requestedCount = mRequestedFds.size();    int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);#endif    // Acquire lock.    mLock.lock();    // Check for poll error.    if (eventCount < 0) {        if (errno == EINTR) {            goto Done;        }        LOGW("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        LOGD("%p ~ pollOnce - timeout", this);#endif        result = ALOOPER_POLL_TIMEOUT;        goto Done;    }    // Handle all events.#if DEBUG_POLL_AND_WAKE    LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);#endif#ifdef LOOPER_USES_EPOLL    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 {                LOGW("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 {                LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "                        "no longer registered.", epollEvents, fd);            }        }    }Done: ;#else    for (size_t i = 0; i < requestedCount; i++) {        const struct pollfd& requestedFd = mRequestedFds.itemAt(i);        short pollEvents = requestedFd.revents;        if (pollEvents) {            if (requestedFd.fd == mWakeReadPipeFd) {                if (pollEvents & POLLIN) {                    awoken();                } else {                    LOGW("Ignoring unexpected poll events 0x%x on wake read pipe.", pollEvents);                }            } else {                int events = 0;                if (pollEvents & POLLIN) events |= ALOOPER_EVENT_INPUT;                if (pollEvents & POLLOUT) events |= ALOOPER_EVENT_OUTPUT;                if (pollEvents & POLLERR) events |= ALOOPER_EVENT_ERROR;                if (pollEvents & POLLHUP) events |= ALOOPER_EVENT_HANGUP;                if (pollEvents & POLLNVAL) events |= ALOOPER_EVENT_INVALID;                pushResponse(events, mRequests.itemAt(i));            }            if (--eventCount == 0) {                break;            }        }    }Done:    // Set mPolling to false and wake up the wakeAndLock() waiters.    mPolling = false;    if (mWaiters != 0) {        mAwake.broadcast();    }#endif#ifdef LOOPER_STATISTICS    nsecs_t pollEndTime = systemTime(SYSTEM_TIME_MONOTONIC);    mSampledPolls += 1;    if (timeoutMillis == 0) {        mSampledZeroPollCount += 1;        mSampledZeroPollLatencySum += pollEndTime - pollStartTime;    } else if (timeoutMillis > 0 && result == ALOOPER_POLL_TIMEOUT) {        mSampledTimeoutPollCount += 1;        mSampledTimeoutPollLatencySum += pollEndTime - pollStartTime                - milliseconds_to_nanoseconds(timeoutMillis);    }    if (mSampledPolls == SAMPLED_POLLS_TO_AGGREGATE) {        LOGD("%p ~ poll latency statistics: %0.3fms zero timeout, %0.3fms non-zero timeout", this,                0.000001f * float(mSampledZeroPollLatencySum) / mSampledZeroPollCount,                0.000001f * float(mSampledTimeoutPollLatencySum) / mSampledTimeoutPollCount);        mSampledPolls = 0;        mSampledZeroPollCount = 0;        mSampledZeroPollLatencySum = 0;        mSampledTimeoutPollCount = 0;        mSampledTimeoutPollLatencySum = 0;    }#endif    // 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                LOGD("%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++) {        const Response& response = mResponses.itemAt(i);        ALooper_callbackFunc callback = response.request.callback;        if (callback) {            int fd = response.request.fd;            int events = response.events;            void* data = response.request.data;#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS            LOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",                    this, callback, fd, events, data);#endif            int callbackResult = callback(fd, events, data);            if (callbackResult == 0) {                removeFd(fd);            }            result = ALOOPER_POLL_CALLBACK;        }    }    return result;}

?

?

热点排行