中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站改版的步驟軟件開發(fā)公司網(wǎng)站

網(wǎng)站改版的步驟,軟件開發(fā)公司網(wǎng)站,為公司做網(wǎng)站,上門做網(wǎng)站公司目錄 一、前言 二、Handler對象 在新啟動的子線程發(fā)送消息(源碼跟蹤) 三、在主線程中,回調(diào) handleMessage 方法的流程是怎樣的呢? 四、總結(jié)說 1、主要由四個部分組成 ①. Message (主要用于攜帶消息)…

目錄

一、前言

二、Handler對象?在新啟動的子線程發(fā)送消息(源碼跟蹤)

三、在主線程中,回調(diào) handleMessage 方法的流程是怎樣的呢?

四、總結(jié)說

1、主要由四個部分組成

①. Message (主要用于攜帶消息)

②. Handler (主要用于發(fā)送和處理消息)

???????③. MessageQueue (它是一個消息隊列)

???????④. Looper (它是一個循環(huán)器)

2、常見用法與源碼解讀

????????1、子線程

????????2、主線程


???????

系列文章

Handler異步消息傳遞機制(一)Handler常用基本用法

Handler異步消息傳遞機制(二)在子線程中創(chuàng)建Handler

Handler異步消息傳遞機制(三)在主線程、子線程中創(chuàng)建Handler,源碼(Android 9.0)解析

Handler異步消息傳遞機制(四)Handler發(fā)送消息流程,源碼(Android 9.0)解析

一、前言

上篇文章我們從源碼角度分析了如何在主線程、子線程創(chuàng)建Handler對象。詳細可參考:Handler異步消息傳遞機制(三)在主線程、子線程中創(chuàng)建Handler,源碼(Android 9.0)徹底解析?

那么創(chuàng)建Handler之后,如何發(fā)送消息呢?這個流程相信大家也已經(jīng)非常熟悉了,我們繼續(xù)以文章?Handler異步消息傳遞機制(一)Handler常用實現(xiàn)方式?的demo為例,然后進行源碼跟蹤解析!

二、Handler對象?在新啟動的子線程發(fā)送消息(源碼跟蹤)

下面是 Handler對象:在新啟動的子線程發(fā)送消息 ?的代碼:

public class DownLoadAppFile {public void download(String urlPath, Handler handler, ProgressBar pb) {try {//下載apk的代碼,這里用線程睡眠模擬Thread.currentThread().sleep(3*1000);} catch (InterruptedException e) {e.printStackTrace();}Message msg = Message.obtain();msg.what =1;//成功//msg.what =2;//失敗handler.sendMessage(msg);//發(fā)送消息}
}

Handler 到底是把 Message 發(fā)送到哪里去了呢?

為什么之后又可以在 Handler 的 handleMessage 方法中重新得到這條Message呢?

接下來我們來看一下發(fā)送消息的源碼:

    public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}

它里面調(diào)用了sendMessageDelayed方法,

往下追蹤

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

我們可以看到 sendMessageDelayed 方法,其中 msg 參數(shù)就是我們發(fā)送的 Message 對象,

而 delayMillis 參數(shù)則表示延遲發(fā)送消息的時間(毫秒),這里默認傳入的為0

往下追蹤

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

我們可以看到 sendMessageAtTime 方法同樣接收兩個參數(shù),其中msg參數(shù)就是我們發(fā)送的 Message 對象,

而 uptimeMillis 參數(shù)則表示發(fā)送消息的時間,SystemClock.uptimeMillis() + delayMillis 即它的值等于自系統(tǒng)開機到當(dāng)前時間的毫秒數(shù)再加上延遲時間。

然后對 MessageQueue 對象 queue 進行了賦值,這個 MessageQueue 又是什么東西呢?

學(xué)過java基礎(chǔ)的可能會馬上想到Queue,基本上一個隊列就是一個先入先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)。

同樣在這里 MessageQueue ?直譯過來就是?消息隊列 的意思,用于將所有收到的消息以隊列的形式進行排列,并提供入隊和出隊的方法。

那么 enqueueMessage 方法就是入隊的方法了,我們來看下這個方法的源碼:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

msg.target = this;? 即msg.target 賦值為 this,也就是把當(dāng)前所在類 Handler,作為 msg 的 target 屬性。

然后將這三個參數(shù)都傳遞到 MessageQueue 的 enqueueMessage 方法中,

也就是說handler發(fā)出的消息,最終會保存到消息隊列中去。

調(diào)用 sendMessage 方法其實最后是調(diào)用了類 MessageQueueen 消息隊列的 enqueueMessage 入隊方法。

那么有了 MessageQueue 消息隊列的 enqueueMessage 入隊方法,它必然有相對應(yīng)的出隊方法。

Handler 對象在新啟動的子線程發(fā)送消息以后,接下來在主線程中,Handler類處理消息的方法 handleMessage 被自動回調(diào)。

三、在主線程中,回調(diào) handleMessage 方法的流程是怎樣的呢?

那么接下來在主線程中,回調(diào) handleMessage 方法的流程是怎樣的呢?

Android的主線程就是 ActivityThread,主線程的入口方法為main,我們繼續(xù)來看一下 ActivityThread 類中main方法的源代碼:

public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");// CloseGuard defaults to true and can be quite spammy.  We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.// It will be in the format "seq=114"long startSeq = 0;if (args != null) {for (int i = args.length - 1; i >= 0; --i) {if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {startSeq = Long.parseLong(args[i].substring(PROC_START_SEQ_IDENT.length()));}}}ActivityThread thread = new ActivityThread();thread.attach(false, startSeq);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

第47行調(diào)用了 Looper.loop() 方法,這個方法內(nèi)部執(zhí)行了消息循環(huán),我們來看下它的源碼:

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();// Allow overriding a threshold with a system prop. e.g.// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'final int thresholdOverride =SystemProperties.getInt("log.looper."+ Process.myUid() + "."+ Thread.currentThread().getName()+ ".slow", 0);boolean slowDeliveryDetected = false;for (;;) {Message msg = queue.next(); // might blockif (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 loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long traceTag = me.mTraceTag;long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;if (thresholdOverride > 0) {slowDispatchThresholdMs = thresholdOverride;slowDeliveryThresholdMs = thresholdOverride;}final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);final boolean needStartTime = logSlowDelivery || logSlowDispatch;final boolean needEndTime = logSlowDispatch;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;final long dispatchEnd;try {msg.target.dispatchMessage(msg);dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}if (logSlowDelivery) {if (slowDeliveryDetected) {if ((dispatchStart - msg.when) <= 10) {Slog.w(TAG, "Drained");slowDeliveryDetected = false;}} else {if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",msg)) {// Once we write a slow delivery log, suppress until the queue drains.slowDeliveryDetected = true;}}}if (logSlowDispatch) {showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();}}

我們可以看到前面幾行代碼,首先對 Looper、MessageQueue 對象進行了賦值,

然后第23行進入了一個死循環(huán)for(?; ;?){ },然后不斷地調(diào)用的 MessageQueue 的 next 方法,

Message msg = queue.next()?很明顯這個 next 方法就是消息隊列的出隊方法。

接下來你會發(fā)現(xiàn)第57行執(zhí)行了 msg.target.dispatchMessage(msg);

其中 msg.targe t就是指的 Handler 對象,你回看一下上面enqueueMessage()方法就可以看出來。

接下來當(dāng)然就要看一看 Handler 中 dispatchMessage 方法的源碼了,如下:

    /*** Handle system messages here.*/public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

在第8行進行判斷,如果 mCallback 不為空,則調(diào)用 mCallback 的 handleMessage 方法,

否則直接調(diào)用Handler的handleMessage方法,并將消息對象作為參數(shù)傳遞過去。

這樣我相信大家就都明白了為什么 handleMessage 方法中可以獲取到之前發(fā)送的消息了吧!

四、總結(jié)說

1、主要由四個部分組成

①. Message (主要用于攜帶消息)

在線程之間傳遞,可在內(nèi)部攜帶少量信息,用于不同線程之間交換數(shù)據(jù)

可以使用what、arg1、arg2字段攜帶整型數(shù)據(jù)

obj字段攜帶Object對象

???????②. Handler (主要用于發(fā)送和處理消息)

1、如果看過Handler源碼,你會知道 Handler 構(gòu)造器,

做了 Looper 對象是否為空的判定,

也就是創(chuàng)建Handler對象之前,必須擁有不為null的Looper對象。

所以子線程創(chuàng)建Handler后會報錯,它需要調(diào)用 prepare()方法。

2、我們平時可以直接在主線程中使用Handler,

那是因為在應(yīng)用程序啟動時,在入口的main方法中已經(jīng)默認為我們創(chuàng)建好了Looper。

主線程中內(nèi)部調(diào)用了Looper的prepareMainLooper方法,

而prepareMainLooper方法里面調(diào)用了Looper的prepare() 方法,所以不會報錯。

3、sendMessage方法用來發(fā)送消息,最終會回到handleMessage方法進行處理。

???????③. MessageQueue (它是一個消息隊列)

1、先入先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)。

主要存放所有通過Handler發(fā)送的消息,

它們會一直存在于隊列中等待被處理

2、每個線程只有一個MessageQueue。

enqueueMessage 入隊方法,next 出隊方法

???????④. Looper (是一個循環(huán)器)

調(diào)用loop方法后,會不斷從MessageQueue 取出待處理的消息,

然后傳遞到handleMessage進行處理

2、常見用法與源碼解讀

????????1、子線程

Handler對象調(diào)用 sendMessage 等方法發(fā)送消息,源碼內(nèi)部在調(diào)用過程中得到 MessageQueue 對象(它是先入先出的隊列),

其實最后是調(diào)用MessageQueue 消息隊列的 enqueueMessage 入隊方法,收到的消息以隊列的形式進行排列

????????2、主線程

Android 的主線程就是 ActivityThread,主線程的入口為main方法,main方法內(nèi)部:

? (1):Looper 調(diào)用 prepareMainLooper 靜態(tài)方法,內(nèi)部會去調(diào)用 prepare 方法(創(chuàng)建 一個Looper對象)

? ? ? ? ????方法內(nèi)部具體:?判讀是否有Looper對象? 有,提示 “每個線程只能創(chuàng)建一個?Looper對象”;沒有,創(chuàng)建一個新的Looper設(shè)置進去

?(2):Looper調(diào)用 loop 方法,loop方法內(nèi)部

? ? ? ? ? ? 首先調(diào)用 myLooper 方法,去取一個Looper對象,

? ? ? ? ? ? 如果Looper對象為空,會拋出一個異常,提示沒有Looper對象;

? ? ? ? ? ? 如果Looper不為空,繼續(xù)執(zhí)行得到 MessageQueueen 消息隊列,然后進行 for循環(huán)操作

? ? ? ? ? ?for循環(huán)里面是 MessageQueueen 對象調(diào)用 next 出隊方法,得到一個個Message 消息,調(diào)用dispatchMessage發(fā)送消息

? ? ? ? ? ?最后通過回調(diào) handleMessage 方法并把 Message 消息依次傳遞過去。

這里采用網(wǎng)上的一張圖,個人感覺圖片概括得很好,就沒必要再去造同樣的輪子了,在新窗口打開可瀏覽大圖

不錯博文可參考:

Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解_郭霖的專欄-CSDN博客_android 異步消息

Android進階——Android消息機制之Looper、Handler、MessageQueen_點擊置頂文章查看博客目錄(全站式導(dǎo)航)-CSDN博客_handler looper

http://m.risenshineclean.com/news/58323.html

相關(guān)文章:

  • 優(yōu)秀創(chuàng)意網(wǎng)站湖北短視頻搜索seo
  • 國內(nèi)專業(yè)網(wǎng)站建設(shè)公司希愛力雙效片用后感受
  • 手機網(wǎng)站制作移動高端網(wǎng)站建設(shè)廈門seo推廣公司
  • 手機h5網(wǎng)站小廣告網(wǎng)站
  • 上海免費網(wǎng)站建設(shè)百度關(guān)鍵詞seo推廣
  • dede網(wǎng)站日志北京優(yōu)化網(wǎng)站推廣
  • 唐山營銷型網(wǎng)站制作東莞seo報價
  • 建設(shè)網(wǎng)站的運行費包括什么搜狗搜索引擎優(yōu)化指南
  • 杭州網(wǎng)站推廣找哪家鄭州百度推廣seo
  • 客服外包在哪個平臺接業(yè)務(wù)談?wù)勀銓eo概念的理解
  • 南京網(wǎng)站開發(fā)南京樂識好臺灣永久免費加密一
  • 沈陽男科醫(yī)院排名最好的是哪家seo 優(yōu)化案例
  • 唐山疫情最新消息今天滿足seo需求的網(wǎng)站
  • 怎么做視頻在線播放網(wǎng)站手機百度極速版
  • 優(yōu)購物官方網(wǎng)站訂單查詢電商怎么推廣自己的產(chǎn)品
  • 采購網(wǎng)站大全寧波正規(guī)seo快速排名公司
  • 長沙哪些公司做網(wǎng)站地推放單平臺
  • 官方:杜絕網(wǎng)絡(luò)平臺發(fā)疫情財優(yōu)化二十條
  • 個體戶營業(yè)執(zhí)照科研做企業(yè)網(wǎng)站嗎域名注冊服務(wù)機構(gòu)
  • 廊坊做網(wǎng)站優(yōu)化百度賬號注冊
  • c 做交易網(wǎng)站谷歌外貿(mào)
  • 誰會在掏寶網(wǎng)上做網(wǎng)站seo查詢 站長之家
  • 網(wǎng)站怎么吸引人淄博網(wǎng)站推廣
  • 陜西省咸陽市建設(shè)銀行網(wǎng)站競價推廣托管服務(wù)
  • 為什么建設(shè)營銷型網(wǎng)站自媒體平臺app下載
  • 房管局網(wǎng)站建設(shè)方案泉州seo按天計費
  • 阿里云的wordpress如何設(shè)置密碼百度搜索引擎優(yōu)化方案
  • 怎么做單頁網(wǎng)站導(dǎo)航怎么進行推廣
  • wordpress清空緩存廣州seo推廣公司
  • 網(wǎng)站tag聚合怎么做網(wǎng)上推廣怎么收費