Handler詳解

Handler詳解

舉例
  • 線程間傳遞數(shù)據(jù)(主線程跟子線程俯邓、兩個(gè)子線程)
簡(jiǎn)介
  • 一套android消息傳遞機(jī)制梦皮。在多線程的應(yīng)用場(chǎng)景中芹缔,將工作線程中需更新UI的操作信息傳遞到 UI主線程驾孔,從而實(shí)現(xiàn)工作線程對(duì)UI的更新處理秋度,最終實(shí)現(xiàn)異步消息的處理炸庞。
  • 使用Handler的原因:將工作線程需操作UI的消息傳遞到主線程,使得主線程可根據(jù)工作線程的需求更新UI荚斯,從而避免線程操作不安全的問(wèn)題
工作流程
  1. 異步通信準(zhǔn)備
  • 在主線程中創(chuàng)建處理器對(duì)象(Looper)埠居、消息隊(duì)列對(duì)象(MessageQueue)、Handler對(duì)象
  1. 消息入隊(duì)
  • 工作線程通過(guò)Handler發(fā)送消息(Message)到消息隊(duì)列(MessageQueue)中
  1. 消息循環(huán)
  • 消息出隊(duì):Looper循環(huán)取出消息隊(duì)列(MessageQueue)中的消息(Message)
  • 消息分發(fā):Looper將取出的消息(Message)發(fā)送給創(chuàng)建該消息的處理者(Handler)
  1. 消息處理
  • 處理者(Handler)接受處理器(Looper)發(fā)送過(guò)來(lái)的消息(Message)
  • 處理者(Handler)根據(jù)消息(Message)進(jìn)行UI操作


核心類
源碼分析
  • 創(chuàng)建Handler
//在主線程中 通過(guò)匿名內(nèi)部類創(chuàng)建Handler類對(duì)象
   private Handler mhandler = new  Handler(){
      // 通過(guò)復(fù)寫handlerMessage()從而確定更新UI的操作
       @Override
          public void handleMessage(Message msg) {
                // 需執(zhí)行的UI操作
                 ...
               }
         };
//創(chuàng)建消息對(duì)象       
   Message message = handler.obtainMessage(MESSAGE_WHAT);
   message.obj = "I am message from work thread";
//發(fā)送
   handler.sendMessage(message);
/** 
  * 源碼分析:Handler的構(gòu)造方法
  * 作用:初始化Handler對(duì)象 & 綁定線程
  *   a. Handler需綁定線程才能使用事期;綁定后拐格,Handler的消息處理會(huì)在綁定的線程中執(zhí)行
  *   b. 綁定方式為先指定Looper對(duì)象,從而綁定了Looper對(duì)象所綁定的線程(因?yàn)長(zhǎng)ooper對(duì)象本已綁定了對(duì)應(yīng)線程)刑赶,即指定了Handler對(duì)象的Looper對(duì)象綁定到了Looper對(duì)象所在的線程
  */
  public Handler() {
       this(null, false);
    }
/** 
  * 分析:this(null, false) = Handler(null捏浊,false)
  */
  public Handler(Callback callback, boolean async) {

            // 1、 指定Looper對(duì)象
            // Looper.myLooper()作用:獲取當(dāng)前線程的Looper對(duì)象撞叨;若線程無(wú)Looper對(duì)象則拋出異常
           // 若線程中無(wú)創(chuàng)建Looper對(duì)象金踪,則也無(wú)法創(chuàng)建Handler對(duì)象
           // 故若需在子線程中創(chuàng)建Handler對(duì)象浊洞,則需先創(chuàng)建Looper對(duì)象
                mLooper = Looper.myLooper();
                if (mLooper == null) {
                    throw new RuntimeException(
                        "Can't create handler inside thread that has not called Looper.prepare()");
                }
                
            // 2、綁定消息隊(duì)列對(duì)象(MessageQueue),獲取該Looper對(duì)象中保存的消息隊(duì)列對(duì)象(MessageQueue)胡岔,保證了handler對(duì)象關(guān)聯(lián)上Looper對(duì)象中MessageQueue
               mQueue = mLooper.mQueue;     
    }
  • 創(chuàng)建主線程時(shí)法希,會(huì)自動(dòng)調(diào)用ActivityThread的1個(gè)靜態(tài)的main();而main()內(nèi)則會(huì)調(diào)用Looper.prepareMainLooper()為主線程生成1個(gè)Looper對(duì)象靶瘸,同時(shí)也會(huì)生成其對(duì)應(yīng)的MessageQueue對(duì)象
//主線程(ActivityThread)創(chuàng)建Looper對(duì)象和對(duì)應(yīng)的消息隊(duì)列對(duì)象(MessageQueue)
public static void main(String[] args) {
     //為主線程創(chuàng)建1個(gè)Looper對(duì)象苫亦,同時(shí)生成1個(gè)消息隊(duì)列對(duì)象(MessageQueue),該方法在主線程(UI線程)創(chuàng)建時(shí)自動(dòng)調(diào)用,即主線程的Looper對(duì)象自動(dòng)生成怨咪,不需手動(dòng)生成
     Looper.prepareMainLooper();
     
     //創(chuàng)建主線程
     ActivityThread thread = new ActivityThread();
     
     //自動(dòng)開(kāi)啟 消息循環(huán)
     Looper.loop();
}
/**
 * 分析:prepareMainLooper()
 */
public static void prepareMainLooper() {

        prepare(false);
        
        //主線程只能有一個(gè)looper
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
/**
 * 分析:prepare(false)
 */
private static void prepare(boolean quitAllowed) {

        // 判斷sThreadLocal是否為null屋剑,否則拋出異常
        //即 Looper.prepare()方法不能被調(diào)用兩次,1個(gè)線程中只能對(duì)應(yīng)1個(gè)Looper實(shí)例
        //注:sThreadLocal是ThreadLocal(線程本地存儲(chǔ)區(qū))對(duì)象诗眨,用于保存線程共享變量     
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
/**
 * 分析:Looper()
 */
private Looper(boolean quitAllowed) {

       //生成消息隊(duì)列(MessageQueue,綁定對(duì)應(yīng)線程)
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
  • 創(chuàng)建消息對(duì)象
 Message message = handler.obtainMessage(MESSAGE_WHAT);
 message.obj = "I am message from work thread";

 /**
  * 分析:handler.obtainMessage(MESSAGE_WHAT);
  * 作用:創(chuàng)建消息對(duì)象
  * 注:創(chuàng)建Message對(duì)象可用關(guān)鍵字new 或 Message.obtain()
  */
  
  public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
  
  public static Message obtain() {
        // Message內(nèi)部維護(hù)了1個(gè)Message池唉匾,用于Message消息對(duì)象的復(fù)用
        // 使用obtain()則是直接從池內(nèi)獲取
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
            // 建議使用obtain()創(chuàng)建消息對(duì)象,避免每次都使用new重新分配內(nèi)存
        }
        // 若池內(nèi)無(wú)消息對(duì)象可復(fù)用匠楚,則還是用關(guān)鍵字new創(chuàng)建
        return new Message();

    }
  • 發(fā)送消息
mHandler.sendMessage(msg);

或者
handler.post(new Runnable() {
          @Override public void run() {
            ...
          }
        });

/**
 *  分析:sendMessage(Message msg)
 */
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
        
    }
    
/**
 * 分析:post(Runnable r)
 */
public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);

        }
   /** 
    * 分析:getPostMessage(r)
    * 作用:將傳入的Runable對(duì)象封裝成1個(gè)消息對(duì)象
    */
  private static Message getPostMessage(Runnable r) {
         //創(chuàng)建1個(gè)消息對(duì)象(Message)
         Message m = Message.obtain();
        
        //將Runable對(duì)象賦值給消息對(duì)象(message)的callback屬性
         m.callback = r;
                        
        //返回該消息對(duì)象
        return m;
        } 
/** 
 * 分析:sendMessageDelayed(msg, 0)
 */
public final boolean sendMessageDelayed(Message msg, long delayMillis)
   {
       if (delayMillis < 0) {
          delayMillis = 0;
     }

  return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
 /** 
  * 分析sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
  */
 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
          // 1. 獲取對(duì)應(yīng)的消息隊(duì)列對(duì)象(MessageQueue)
         MessageQueue queue = mQueue;

         // 2. 調(diào)用了enqueueMessage方法
        return enqueueMessage(queue, msg, uptimeMillis);
                }
/** 
 * 分析:enqueueMessage(queue, msg, uptimeMillis)
 */
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    // 1. 將msg.target賦值為this,即把當(dāng)前的Handler實(shí)例對(duì)象作為msg的target屬性
    msg.target = this;       
  // 2. 調(diào)用消息隊(duì)列的enqueueMessage()巍膘,即:Handler發(fā)送的消息,最終是保存到消息隊(duì)列
  return queue.enqueueMessage(msg, uptimeMillis);
       }
 /** 
  * 定義:屬于消息隊(duì)列類(MessageQueue)的方法
  * 作用:入隊(duì)芋簿,即將消息根據(jù)時(shí)間放入到消息隊(duì)列中(Message ->> MessageQueue)
  * 采用單鏈表實(shí)現(xiàn):提高插入消息峡懈、刪除消息的效率
  */
  boolean enqueueMessage(Message msg, long when) {

      ...// 僅貼出關(guān)鍵代碼

      synchronized (this) {

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;

       // 判斷消息隊(duì)列里有無(wú)消息
       // a. 若無(wú),則將當(dāng)前插入的消息作為隊(duì)頭,若此時(shí)消息隊(duì)列處于等待狀態(tài)与斤,則喚醒
       if (p == null || when == 0 || when < p.when) {
           msg.next = p;
           mMessages = msg;
           needWake = mBlocked;
          } else {
          needWake = mBlocked && p.target == null && msg.isAsynchronous();
          Message prev;

      // b. 判斷消息隊(duì)列里有消息逮诲,則根據(jù)消息(Message)觸發(fā)的時(shí)間插入到隊(duì)列中
         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從消息隊(duì)列取消息并分發(fā)給Handler
/** 
  * 源碼分析: Looper.loop()
  * 作用:消息循環(huán),即從消息隊(duì)列中獲取消息幽告、分發(fā)消息到Handler
  */
  public static void loop() {
        
        ...// 僅貼出關(guān)鍵代碼

        // 獲取當(dāng)前Looper的消息隊(duì)列梅鹦,myLooper()作用:返回sThreadLocal存儲(chǔ)的Looper實(shí)例;若me為null 則拋出異常冗锁,即loop()執(zhí)行前必須執(zhí)行prepare()齐唆,從而創(chuàng)建1個(gè)Looper實(shí)例
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            
            // 獲取Looper實(shí)例中的消息隊(duì)列對(duì)象(MessageQueue)
           final MessageQueue queue = me.mQueue;
       // 消息循環(huán)
            for (;;) {
            
            //從消息隊(duì)列中取出消息,next():取出消息隊(duì)列里的消息冻河,若取出的消息為空箍邮,則線程阻塞
            Message msg = queue.next(); 
            if (msg == null) {
                return;
            }
            
            // 派發(fā)消息到對(duì)應(yīng)的Handler,把消息Message派發(fā)給消息對(duì)象msg的target屬性叨叙,target屬性實(shí)際是1個(gè)handler對(duì)象
            msg.target.dispatchMessage(msg);

           // 釋放消息占據(jù)的資源
           msg.recycleUnchecked();
        }
}
/** 
  * 分析:queue.next()
  * 定義:屬于消息隊(duì)列類(MessageQueue)中的方法
  * 作用:出隊(duì)消息锭弊,即從 消息隊(duì)列中 移出該消息
  */
  Message next() {

        ...// 僅貼出關(guān)鍵代碼

        // 該參數(shù)用于確定消息隊(duì)列中是否還有消息,從而決定消息隊(duì)列應(yīng)處于出隊(duì)消息狀態(tài) or 等待狀態(tài)
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

        // nativePollOnce方法在native層擂错,若是nextPollTimeoutMillis為-1味滞,此時(shí)消息隊(duì)列處于等待狀態(tài) 
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
     
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;

            // 出隊(duì)消息,即從消息隊(duì)列中取出消息:按創(chuàng)建Message對(duì)象的時(shí)間順序
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 取出了消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    
                    msg.markInUse();
                    return msg;
                }
            } else {

                // 若 消息隊(duì)列中已無(wú)消息,則將nextPollTimeoutMillis參數(shù)設(shè)為-1
                // 下次循環(huán)時(shí)剑鞍,消息隊(duì)列則處于等待狀態(tài)
                nextPollTimeoutMillis = -1;
            }

            ......
        }
           .....
       }
}
/** 
  * 分析:dispatchMessage(msg)
  * 定義:屬于處理者類(Handler)中的方法
  * 作用:派發(fā)消息到對(duì)應(yīng)的Handler實(shí)例 & 根據(jù)傳入的msg作出對(duì)應(yīng)的操作
  */
  public void dispatchMessage(Message msg) {

    // 若msg.callback屬性不為空昨凡,則代表使用了post(Runnable r)發(fā)送消息,則執(zhí)行handleCallback(msg)蚁署,即回調(diào)Runnable對(duì)象里復(fù)寫的run()
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }

            // 若msg.callback屬性為空便脊,則代表使用了sendMessage(Message msg)發(fā)送消息,則執(zhí)行handleMessage(msg)光戈,即回調(diào)復(fù)寫的handleMessage(msg)
            
            handleMessage(msg);

        }
    }

  /** 
   * 分析:handleMessage(msg)
   * 在創(chuàng)建Handler實(shí)例時(shí)復(fù)寫
   */
   public void handleMessage(Message msg) {  
          ... // 創(chuàng)建Handler實(shí)例時(shí)復(fù)寫
   } 
  • MessageQueue native中nativeWake(long ptr)跟nativePollOnce(long ptr, int timeoutMillis)
/**
 * 分析:android_os_MessageQueue.cpp中nativeWake(long ptr)
 */
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake();
}

/**
 * 指向了Looper.cpp的wake()
 */
void NativeMessageQueue::wake() {
    mLooper->wake();
}

/**
 * Looper.cpp中wake()
 */
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ wake", this);
#endif
    ssize_t nWrite;
    do {
        // 向管道m(xù)WakeWritePipeFd寫入字符哪痰,用來(lái)喚醒線程
        nWrite = write(mWakeWritePipeFd, "W", 1);
    } while (nWrite == -1 && errno == EINTR);
    if (nWrite != 1) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}
/**
 * 分析:android_os_MessageQueue.cpp中nativePollOnce(long ptr, int timeoutMillis)
 */
 static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
/**
 * 指向了Looper.cpp中的pollOnce()
 */
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}
/**
 * Looper.cpp中pollOnce
 */
 int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        // 先處理沒(méi)有Callback方法的 Response事件
        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
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        if (result != 0) {
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
        //處理內(nèi)部輪詢
        result = pollInner(timeoutMillis);
    }
}
/**
 * pollInner(int timeoutMillis)
 */
 int Looper::pollInner(int timeoutMillis) {
    // 調(diào)整超時(shí)時(shí)間根據(jù)下一條消息
    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;
        }
    
    int result = ALOOPER_POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    
    //等待事件發(fā)生或者超時(shí),向管道寫端寫入字符久妆,則該方法會(huì)返回
    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;
        }
        result = ALOOPER_POLL_ERROR;
        goto Done;
    }
    // Check for poll timeout.
    if (eventCount == 0) {
        result = ALOOPER_POLL_TIMEOUT;
        goto Done;
    }
    
    // 循環(huán)遍歷晌杰,處理所有的事件
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        
        //通過(guò)管道讀端被喚醒
        if (fd == mWakeReadPipeFd) {
            if (epollEvents & EPOLLIN) {
            //去把管道數(shù)據(jù)中數(shù)據(jù)讀完
               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;
                //處理request,生成對(duì)應(yīng)的respone對(duì)象,push到響應(yīng)數(shù)組
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
Done: ;
    // 再處理Native的Message镇饺,調(diào)用相應(yīng)回調(diào)方法
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();
                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();
    
    //處理帶有Callback()方法的Response事件乎莉,執(zhí)行Reponse相應(yīng)的回調(diào)方法
    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;
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);
            }
            
            //清除reponse引用的回調(diào)方法
            response.request.callback.clear();
            result = ALOOPER_POLL_CALLBACK;
        }
    }
    return result;
}
/**
 * 讀取管道數(shù)據(jù)
 */
void Looper::awoken() {
    char buffer[16];
    ssize_t nRead;
    do {
        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
}
總結(jié)
  1. 應(yīng)用程序主線程創(chuàng)建時(shí)送讲,則自動(dòng)為主線程
    • 創(chuàng)建一個(gè)處理器對(duì)象Looper
    • 創(chuàng)建消息隊(duì)列對(duì)象(MessageQueue)
    • 進(jìn)入消息循環(huán)
  2. 創(chuàng)建Handler實(shí)例奸笤,綁定所在的當(dāng)前線程和對(duì)應(yīng)的消息隊(duì)列
  3. 創(chuàng)建消息對(duì)象(Message、Runnable)
  4. 隨著Looper對(duì)象的無(wú)限消息循環(huán)哼鬓,從消息隊(duì)列(MessageQueue)中取出Handler發(fā)送的消息监右,不斷將消息發(fā)送到對(duì)應(yīng)的Handler,根據(jù)回調(diào)方法進(jìn)行相關(guān)的處理。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末异希,一起剝皮案震驚了整個(gè)濱河市健盒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌称簿,老刑警劉巖扣癣,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異憨降,居然都是意外死亡父虑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門授药,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)士嚎,“玉大人,你說(shuō)我怎么就攤上這事悔叽±绸茫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵娇澎,是天一觀的道長(zhǎng)笨蚁。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么赚窃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任册招,我火速辦了婚禮,結(jié)果婚禮上勒极,老公的妹妹穿的比我還像新娘是掰。我一直安慰自己,他們只是感情好辱匿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布键痛。 她就那樣靜靜地躺著,像睡著了一般匾七。 火紅的嫁衣襯著肌膚如雪絮短。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天昨忆,我揣著相機(jī)與錄音丁频,去河邊找鬼。 笑死邑贴,一個(gè)胖子當(dāng)著我的面吹牛席里,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拢驾,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼奖磁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了繁疤?” 一聲冷哼從身側(cè)響起咖为,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稠腊,沒(méi)想到半個(gè)月后躁染,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡架忌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吞彤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳖昌。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡备畦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出许昨,到底是詐尸還是另有隱情懂盐,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布糕档,位于F島的核電站莉恼,受9級(jí)特大地震影響拌喉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俐银,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一尿背、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捶惜,春花似錦田藐、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至踊餐,卻和暖如春景醇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吝岭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工三痰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窜管。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓散劫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親微峰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舷丹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 在Android開(kāi)發(fā)的多線程應(yīng)用場(chǎng)景中抒钱,Handler機(jī)制十分常用 今天蜓肆,我將手把手帶你深入分析Handle...
    BrotherChen閱讀 474評(píng)論 0 0
  • 一、Handler的引入: 我們都知道谋币,Android UI是線程不安全的仗扬,如果在子線程中嘗試進(jìn)行UI操作,程序就...
    Candy有雪吃閱讀 545評(píng)論 0 2
  • Handler理解: 一蕾额、基礎(chǔ)解讀 Android 的Handler 用于處理消息隊(duì)列 handler 牛津詞典的...
    霄何閱讀 1,305評(píng)論 0 1
  • 本文包含與Handler有關(guān)的以下問(wèn)題 1.Handler的作用2.為什么Android中要設(shè)計(jì)為只能在UI線程中...
    YoungTa0閱讀 1,132評(píng)論 0 1
  • Handler There are two main uses for a HandlerHandler的兩個(gè)主要...
    Little丶Jerry閱讀 358評(píng)論 0 0