Handler源碼是什么

這篇文章主要介紹“Handler源碼是什么”的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“Handler源碼是什么”文章能幫助大家解決問題。

公司主營業(yè)務(wù):成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出愛輝免費(fèi)做網(wǎng)站回饋大家。

Handler機(jī)制是Android中相當(dāng)經(jīng)典的異步消息機(jī)制,在Android發(fā)展的歷史長河中扮演著很重要的角色,無論是我們直接面對的應(yīng)用層還是FrameWork層,使用的場景還是相當(dāng)?shù)亩唷?/p>

分析源碼一探究竟。

從一個(gè)常見的用法說起:

private Button mBtnTest;private Handler mTestHandler = new Handler(){   @Override
   public void handleMessage(Message msg) {       switch (msg.what){           case 1:
               mBtnTest.setText("收到消息1");
       }
   }
};@Overrideprotected void onCreate(final Bundle savedInstanceState) {   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   mBtnTest = (Button) findViewById(R.id.btn_test);   new Thread(new Runnable() {       @Override
       public void run() {           try {
               Thread.sleep(3000);
               mTestHandler.sendEmptyMessage(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
   }).start();
}

在對某件實(shí)物進(jìn)一步了解之前,我們要先對該事物的價(jià)值意義有一個(gè)理解,即他是做什么的,再明白事物產(chǎn)生或發(fā)生時(shí)做了什么,結(jié)束時(shí)又會有什么樣的結(jié)果。

我們要討論研究的是這個(gè)過程到底經(jīng)歷了什么,是發(fā)生什么因,再經(jīng)歷什么產(chǎn)生這個(gè)果。

當(dāng)調(diào)用Handler發(fā)送消息相關(guān)方法時(shí),會把這個(gè)消息發(fā)送到哪兒去?從上面的示例代碼中可以看到消息最終還是會回到Handler手上,由他自己處理。我們要搞清楚的就是這個(gè)消息由發(fā)到收的過程。

消息會發(fā)送到哪兒去?

mTestHandler.sendEmptyMessage(1);

我們追隨sendEmptyMessage()方法下去:

Handler無論以何種方式發(fā)送何種消息,都會經(jīng)過到sendMessageAtTime()方法:

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

而此方法會先判斷當(dāng)前Handler的mQueue對象是否為空,再調(diào)用enqueueMessage()方法,從字面意思不難理解是將該消息入隊(duì)保存起來。再看enqueueMessage()方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
   msg.target = this;   if (mAsynchronous) {
       msg.setAsynchronous(true);
   }   return queue.enqueueMessage(msg, uptimeMillis);
}public final class Message implements Parcelable {   //....
   Handler target;
}

該方法會先將Message和當(dāng)前Handler綁定起來,不難理解當(dāng)需要處理Message時(shí)直接甩給綁定他的Handler就是了。再調(diào)用queue.enqueueMessage()方法正式入隊(duì),而queue對象到底是一個(gè)什么樣的對象?由單向鏈表實(shí)現(xiàn)的消息隊(duì)列。queue.enqueueMessage()方法就是遍歷鏈表將消息插入表尾保存起來,而從queue取消息就是把表頭的Message拿出來。

接著來搞清楚queue他是何時(shí)怎樣創(chuàng)建的?來看Handler的構(gòu)造函數(shù)。

public Handler(Callback callback, boolean async) {
   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;
}

Handler的構(gòu)造方法會先調(diào)用Looper.myLooper()方法看能不能獲取一個(gè)Looper對象,如果獲取不到程序就直接蹦了。再從該Looper對象中獲取我們需要的消息隊(duì)列。

Looper到底是一個(gè)怎樣的對象,有這怎樣的身份,在Handler機(jī)制中扮演這怎樣的角色?來看myLooper()方法:

public static @Nullable Looper myLooper() {   return sThreadLocal.get();
}

myLooper()方法會直接就從sThreadLocal對象中獲取Looper,而sThreadLocal是一個(gè)ThreadLocal類對象,而ThreadLocal類說白了就是通過他存儲的對象是線程私有的。

static final ThreadLocal sThreadLocal = new ThreadLocal();

調(diào)用get()方法直接從ThreadLocal中獲取Looper,接下來就得看是何時(shí)set()將Loooper對象保存到ThreadLocal中去的。Looper.prepare()方法:

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));
}private Looper(boolean quitAllowed) {
   mQueue = new MessageQueue(quitAllowed);
   mThread = Thread.currentThread();
}

從這段源碼可以看出,Looper不僅是線程私有的還是唯一不可替換。Looper對象創(chuàng)建時(shí)會初始化MessageQueue()對象,正是我們需要的隊(duì)列。
之所以最上面的示例代碼中我們并沒有調(diào)用prepare()方法初始化Looper,程序也沒有崩潰,那是因?yàn)樵贏ctivityThread的Main方法中就已經(jīng)初始化了Looper對象。

public final class ActivityThread {   //......
   public static void main(String[] args) {
       Looper.prepareMainLooper();
   }   //......}

到此我們算是明白消息會發(fā)送到哪兒去了,現(xiàn)在就要知道的是怎么取出消息交給Handler處理的。

首先MessageQueue封裝有完整的添加(入隊(duì))和獲取/刪除(出隊(duì))方法,MessageQueeue.next()方法將鏈表當(dāng)中表頭第一個(gè)消息取出。

Message next() {   //..........
   for (;;) {       if (nextPollTimeoutMillis != 0) {
           Binder.flushPendingCommands();
       }
       nativePollOnce(ptr, nextPollTimeoutMillis);       synchronized (this) {           final long now = SystemClock.uptimeMillis();
           Message prevMsg = null;
           Message msg = mMessages;           if (msg != null && msg.target == null) {               do {
                   prevMsg = msg;
                   msg = msg.next;
               } while (msg != null && !msg.isAsynchronous());
           }           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;                   if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                   msg.markInUse();                   return msg;
               }
           } else {
               nextPollTimeoutMillis = -1;
           }           if (mQuitting) {
               dispose();               return null;
           }           //............
       }       //..............
   }
}

代碼雖然比較多,我們從第三行和第39行開始說起。next()方法實(shí)際是一個(gè)死循環(huán),會一直從當(dāng)前隊(duì)列中去取Message,即使當(dāng)前隊(duì)列沒有消息可取,也不會跳出循環(huán),會一直執(zhí)行,直到能夠從隊(duì)列中取到消息next()方法才會執(zhí)行結(jié)束。

其次當(dāng)Looper調(diào)用quit()方法,mQuitting變量為ture時(shí)會跳出死循環(huán),next()方法返回null方法也會執(zhí)行結(jié)束。

上面提到在ActivityThread中的main()方法中會初始化Looper,其實(shí)在不久之后便會開始從隊(duì)列中取消息。

public static void main(String[] args) {   //......
   Looper.prepareMainLooper();
   ActivityThread thread = new ActivityThread();
   thread.attach(false);   if (sMainThreadHandler == null) {
       sMainThreadHandler = thread.getHandler();
   }   if (false) {
       Looper.myLooper().setMessageLogging(new
               LogPrinter(Log.DEBUG, "ActivityThread"));
   }
   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   Looper.loop();   throw new RuntimeException("Main thread loop unexpectedly exited");
}
調(diào)用Looper.loop()方法就會開始遍歷取消息。public static void loop() {for (;;) {
   Message msg = queue.next(); // might block
   if (msg == null) {       return;
   }   final Printer logging = me.mLogging;   if (logging != null) {
       logging.println(">>>>> Dispatching to " + msg.target + " " +
               msg.callback + ": " + msg.what);
   }   final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;   final long traceTag = me.mTraceTag;   if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
       Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
   }   final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();   final long end;   try {
       msg.target.dispatchMessage(msg);
       end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
   } finally {       if (traceTag != 0) {
           Trace.traceEnd(traceTag);
       }
   }
}

loop()方法中也是一個(gè)死循環(huán),調(diào)用queue.nex()方法開始阻塞式取消息,只有手動讓Looper停止,next()方法才會返回null。

取到消息后,調(diào)用dispatchMessage()方法把消息交由Handler處理。

msg.target.dispatchMessage(msg);

public void dispatchMessage(Message msg) {   if (msg.callback != null) {
       handleCallback(msg);
   } else {       if (mCallback != null) {           if (mCallback.handleMessage(msg)) {               return;
           }
       }
       handleMessage(msg);
   }
}

不僅可以給Handler設(shè)置回調(diào)接口,Message也行。默認(rèn)情況下會回調(diào)handleMessage()方法。

本以為說得差不多了,其實(shí)還有一個(gè)關(guān)鍵的問題。我們是在主線程中執(zhí)行的loop()方法,死循環(huán)為什么沒有造成Activity阻塞卡死?查閱資料Android中為什么主線程不會因?yàn)長ooper.loop()里的死循環(huán)卡死后得知next()方法中會執(zhí)行一個(gè)重要方法。

nativePollOnce(ptr, nextPollTimeoutMillis);

大佬分析得很好,我就不多說了。提一點(diǎn),我們發(fā)送的延時(shí)消息,會通過Message字段/變量when,將時(shí)長保存下來,延時(shí)也是通過這個(gè)方法做到的。

Message next() {   final long now = SystemClock.uptimeMillis();   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 {           //......
       }
   }
}

Handler發(fā)送消息會將消息保存到Looper維護(hù)的消息隊(duì)列MessageQueue中去,而Looper會死循環(huán)一直從隊(duì)列中取消息,取到消息后會交由Message綁定的Handler回調(diào)處理。

關(guān)于“Handler源碼是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點(diǎn)。

分享標(biāo)題:Handler源碼是什么
標(biāo)題URL:http://bm7419.com/article46/jcsceg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、面包屑導(dǎo)航品牌網(wǎng)站設(shè)計(jì)、建站公司移動網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司