UI線程,即主線程。為何將UI線程和其他事物線程,是由于其他事務處理會需要更多的時間去加載,也就是所謂的耗時操作,這樣不會導致頁面加載需要很久(至少畫面出來了,數(shù)據(jù)可以略慢)。設計UI線程是為了使得程序能夠獨立完成界面加載不受其他線程影響速度。

網站建設哪家好,找創(chuàng)新互聯(lián)!專注于網頁設計、網站建設、微信開發(fā)、微信小程序開發(fā)、集團企業(yè)網站建設等服務項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了靈寶免費建站歡迎大家使用!
UI線程就是主線程 你在更新UI時必須要在主線程中更新 所以說也叫UI線程
是的,只是叫法上的不同。因為Android處于安全性考慮,只允許在主線程中操作UI,所以也叫UI線程。
Android 中線程可分為 主線程 和 子線程 兩類,其中主線程也就是 UI線程 ,它的主要這作用就是運行四大組件、處理界面交互。子線程則主要是處理耗時任務,也是我們要重點分析的。
首先 Java 中的各種線程在 Android 里是通用的,Android 特有的線程形態(tài)也是基于 Java 的實現(xiàn)的,所以有必要先簡單的了解下 Java 中的線程,本文主要包括以下內容:
在 Java 中要創(chuàng)建子線程可以直接繼承 Thread 類,重寫 run() 方法:
或者實現(xiàn) Runnable 接口,然后用Thread執(zhí)行Runnable,這種方式比較常用:
簡單的總結下:
Callable 和 Runnable 類似,都可以用來處理具體的耗時任務邏輯的,但是但具體的差別在哪里呢?看一個小例子:
定義 MyCallable 實現(xiàn)了 Callable 接口,和之前 Runnable 的 run() 方法對比下, call() 方法是有返回值的哦,泛型就是返回值的類型:
一般會通過線程池來執(zhí)行 Callable (線程池相關內容后邊會講到),執(zhí)行結果就是一個 Future 對象:
可以看到,通過線程池執(zhí)行 MyCallable 對象返回了一個 Future 對象,取出執(zhí)行結果。
Future 是一個接口,從其內部的方法可以看出它提供了取消任務(有坑!!!)、判斷任務是否完成、獲取任務結果的功能:
Future 接口有一個 FutureTask 實現(xiàn)類,同時 FutureTask 也實現(xiàn)了 Runnable 接口,并提供了兩個構造函數(shù):
用 FutureTask 一個參數(shù)的構造函數(shù)來改造下上邊的例子:
FutureTask 內部有一個 done() 方法,代表 Callable 中的任務已經結束,可以用來獲取執(zhí)行結果:
所以 Future + Callable 的組合可以更方便的獲取子線程任務的執(zhí)行結果,更好的控制任務的執(zhí)行,主要的用法先說這么多了,其實 AsyncTask 內部也是類似的實現(xiàn)!
注意, Future 并不能取消掉運行中的任務,這點在后邊的 AsyncTask 解析中有提到。
Java 中線程池的具體的實現(xiàn)類是 ThreadPoolExecutor ,繼承了 Executor 接口,這些線程池在 Android 中也是通用的。使用線程池的好處:
常用的構造函數(shù)如下:
一個常規(guī)線程池可以按照如下方式來實現(xiàn):
執(zhí)行任務:
基于 ThreadPoolExecutor ,系統(tǒng)擴展了幾類具有新特性的線程池:
線程池可以通過 execute() 、 submit() 方法開始執(zhí)行任務,主要差別從方法的聲明就可以看出,由于 submit() 有返回值,可以方便得到任務的執(zhí)行結果:
要關閉線程池可以使用如下方法:
IntentService 是 Android 中一種特殊的 Service,可用于執(zhí)行后臺耗時任務,任務結束時會自動停止,由于屬于系統(tǒng)的四大組件之一,相比一般線程具有較高的優(yōu)先級,不容易被殺死。用法和普通 Service 基本一致,只需要在 onHandleIntent() 中處理耗時任務即可:
至于 HandlerThread,它是 IntentService 內部實現(xiàn)的重要部分,細節(jié)內容會在 IntentService 源碼中說到。
IntentService 首次創(chuàng)建被啟動的時候其生命周期方法 onCreate() 會先被調用,所以我們從這個方法開始分析:
這里出現(xiàn)了 HandlerThread 和 ServiceHandler 兩個類,先搞明白它們的作用,以便后續(xù)的分析。
首先看 HandlerThread 的核心實現(xiàn):
首先它繼承了 Thread 類,可以當做子線程來使用,并在 run() 方法中創(chuàng)建了一個消息循環(huán)系統(tǒng)、開啟消息循環(huán)。
ServiceHandler 是 IntentService 的內部類,繼承了 Handler,具體內容后續(xù)分析:
現(xiàn)在回過頭來看 onCreate() 方法主要是一些初始化的操作, 首先創(chuàng)建了一個 thread 對象,并啟動線程,然后用其內部的 Looper 對象 創(chuàng)建一個 mServiceHandler 對象,將子線程的 Looper 和 ServiceHandler 建立了綁定關系,這樣就可以使用 mServiceHandler 將消息發(fā)送到子線程去處理了。
生命周期方法 onStartCommand() 方法會在 IntentService 每次被啟動時調用,一般會這里處理啟動 IntentService 傳遞 Intent 解析攜帶的數(shù)據(jù):
又調用了 start() 方法:
就是用 mServiceHandler 發(fā)送了一條包含 startId 和 intent 的消息,消息的發(fā)送還是在主線程進行的,接下來消息的接收、處理就是在子線程進行的:
當接收到消息時,通過 onHandleIntent() 方法在子線程處理 intent 對象, onHandleIntent() 方法執(zhí)行結束后,通過 stopSelf(msg.arg1) 等待所有消息處理完畢后終止服務。
為什么消息的處理是在子線程呢?這里涉及到 Handler 的內部消息機制,簡單的說,因為 ServiceHandler 使用的 Looper 對象就是在 HandlerThread 這個子線程類里創(chuàng)建的,并通過 Looper.loop() 開啟消息循環(huán),不斷從消息隊列(單鏈表)中取出消息,并執(zhí)行,截取 loop() 的部分源碼:
dispatchMessage() 方法間接會調用 handleMessage() 方法,所以最終 onHandleIntent() 就在子線程中劃線執(zhí)行了,即 HandlerThread 的 run() 方法。
這就是 IntentService 實現(xiàn)的核心,通過 HandlerThread + Hanlder 把啟動 IntentService 的 Intent 從主線程切換到子線程,實現(xiàn)讓 Service 可以處理耗時任務的功能!
AsyncTask 是 Android 中輕量級的異步任務抽象類,它的內部主要由線程池以及 Handler 實現(xiàn),在線程池中執(zhí)行耗時任務并把結果通過 Handler 機制中轉到主線程以實現(xiàn)UI操作。典型的用法如下:
從 Android3.0 開始,AsyncTask 默認是串行執(zhí)行的:
如果需要并行執(zhí)行可以這么做:
AsyncTask 的源碼不多,還是比較容易理解的。根據(jù)上邊的用法,可以從 execute() 方法開始我們的分析:
看到 @MainThread 注解了嗎?所以 execute() 方法需要在主線程執(zhí)行哦!
進而又調用了 executeOnExecutor() :
可以看到,當任務正在執(zhí)行或者已經完成,如果又被執(zhí)行會拋出異常!回調方法 onPreExecute() 最先被執(zhí)行了。
傳入的 sDefaultExecutor 參數(shù),是一個自定義的串行線程池對象,所有任務在該線程池中排隊執(zhí)行:
可以看到 SerialExecutor 線程池僅用于任務的排隊, THREAD_POOL_EXECUTOR 線程池才是用于執(zhí)行真正的任務,就是我們線程池部分講到的 ThreadPoolExecutor :
再回到 executeOnExecutor() 方法中,那么 exec.execute(mFuture) 就是觸發(fā)線程池開始執(zhí)行任務的操作了。
那 executeOnExecutor() 方法中的 mWorker 是什么? mFuture 是什么?答案在 AsyncTask 的構造函數(shù)中:
原來 mWorker 是一個 Callable 對象, mFuture 是一個 FutureTask 對象,繼承了 Runnable 接口。所以 mWorker 的 call() 方法會在 mFuture 的 run() 方法中執(zhí)行,所以 mWorker 的 call() 方法在線程池得到執(zhí)行!
同時 doInBackground() 方法就在 call() 中方法,所以我們自定義的耗時任務邏輯得到執(zhí)行,不就是我們第二部分講的那一套嗎!
doInBackground() 的返回值會傳遞給 postResult() 方法:
就是通過 Handler 將最終的耗時任務結果從子線程發(fā)送到主線程,具體的過程是這樣的, getHandler() 得到的就是 AsyncTask 構造函數(shù)中初始化的 mHandler , mHander 又是通過 getMainHandler() 賦值的:
可以在看到 sHandler 是一個 InternalHandler 類對象:
所以 getHandler() 就是在得到在主線程創(chuàng)建的 InternalHandler 對象,所以
就可以完成耗時任務結果從子線程到主線程的切換,進而可以進行相關UI操作了。
當消息是 MESSAGE_POST_RESULT 時,代表任務執(zhí)行完成, finish() 方法被調用:
如果任務沒有被取消的話執(zhí)行 onPostExecute() ,否則執(zhí)行 onCancelled() 。
如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被執(zhí)行,根據(jù)之前的用法可以 onProgressUpdate() 的執(zhí)行需要我們手動調用 publishProgress() 方法,就是通過 Handler 來發(fā)送進度數(shù)據(jù):
進行中的任務如何取消呢?AsyncTask 提供了一個 cancel(boolean mayInterruptIfRunning) ,參數(shù)代表是否中斷正在執(zhí)行的線程任務,但是呢并不靠譜, cancel() 的方法注釋中有這么一段:
大致意思就是調用 cancel() 方法后, onCancelled(Object) 回調方法會在 doInBackground() 之后被執(zhí)行而 onPostExecute() 將不會被執(zhí)行,同時你應該 doInBackground() 回調方法中通過 isCancelled() 來檢查任務是否已取消,進而去終止任務的執(zhí)行!
所以只能自己動手了:
AsyncTask 整體的實現(xiàn)流程就這些了,源碼是最好的老師,自己跟著源碼走一遍有些問題可能就豁然開朗了!
稍微有過Andorid開發(fā)經驗的同學都知道,Android開發(fā)中涉及到UI變動的操作,必須在主線程中執(zhí)行, 否則會crash
這就需要我們將代碼拋到主線程執(zhí)行。
第一種方式,是通過Activity.runOnUiThread()來做。這不是一個好方法,畢竟Activity這種東西,在子線程中可遇不可求。也千萬不要因此而將Activity傳來傳去,甚至對Context進行強轉,那樣太過難看。
那么,只剩下通過Handler手動將代碼拋到主線程了。這就需要,Handler具有主線程的Looper對象。具體的原因可以參考我之前的博客:【Android】結合源碼解析Android消息隊列工作流程 。
兩種實現(xiàn)方式:
1. 在主線程中創(chuàng)建Handler
2. 直接通過MainLooper,構造handler
在一個Android 程序開始運行的時候,會單獨啟動一個Process。默認的情況下,所有這個程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的兩種,除此之外還有Content Provider和Broadcast Receiver)都會跑在這個Process。
一個Android 程序默認情況下也只有一個Process,但一個Process下卻可以有許多個Thread。在這么多Thread當中,有一個Thread,我們稱之為UI Thread。UI Thread在Android程序運行的時候就被創(chuàng)建,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示、更新和控件交互。在Android程序創(chuàng)建之初,一個Process呈現(xiàn)的是單線程模型,所有的任務都在一個線程中運行。因此,我們認為,UI Thread所執(zhí)行的每一個函數(shù),所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網絡,下載數(shù)據(jù),查詢數(shù)據(jù)庫等),都應該交由子線程去執(zhí)行,以免阻塞主線程。
那么,UI Thread如何和其他Thread一起工作呢?常用方法是:
誕生一個主線程的Handler物件,當做Listener去讓子線程能將訊息Push到主線程的Message Quene里,以便觸發(fā)主線程的handlerMessage()函數(shù),讓主線程知道子線程的狀態(tài),并在主線程更新UI。
                文章題目:android的ui線程,安卓子線程可以更新ui嗎
                
                文章分享:http://www.chinadenli.net/article24/dsdgcje.html
            
成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站內鏈、網站營銷、商城網站、微信小程序、品牌網站制作、微信公眾號
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)
