導航:首頁 > 操作系統 > android線程池工具

android線程池工具

發布時間:2025-05-22 08:02:25

android中的線程狀態 - AsyncTask詳解

在操作系統中,線程是操作系統調度的最小單元,同時線程又是一種受限的系統資源,即線程不可能無限制地產生,並且 線程的創建和銷毀都會有相應的開銷。 當系統中存在大量的線程時,系統會通過會時間片輪轉的方式調度每個線程,因此線程不可能做到絕對的並行。

如果在一個進程中頻繁地創建和銷毀線程,顯然不是高效的做法。正確的做法是採用線程池,一個線程池中會緩存一定數量的線程,通過線程池就可以避免因為頻繁創建和銷毀線程所帶來的系統開銷。

AsyncTask是一個抽象類,它是由Android封裝的一個輕量級非同步類(輕量體現在使用方便、代碼簡潔),它可以在線程池中執行後台任務,然後把執行的進度和最終結果傳遞給主線程並在主線程中更新UI。

AsyncTask的內部封裝了 兩個線程池 (SerialExecutor和THREAD_POOL_EXECUTOR)和 一個Handler (InternalHandler)。

其中 SerialExecutor線程池用於任務的排隊,讓需要執行的多個耗時任務,按順序排列 THREAD_POOL_EXECUTOR線程池才真正地執行任務 InternalHandler用於從工作線程切換到主線程

1.AsyncTask的泛型參數

AsyncTask是一個抽象泛型類。

其中,三個泛型類型參數的含義如下:

Params: 開始非同步任務執行時傳入的參數類型;

Progress: 非同步任務執行過程中,返回下載進度值的類型;

Result: 非同步任務執行完成後,返回的結果類型;

如果AsyncTask確定不需要傳遞具體參數,那麼這三個泛型參數可以用Void來代替。

有了這三個參數類型之後,也就控制了這個AsyncTask子類各個階段的返回類型,如果有不同業務,我們就需要再另寫一個AsyncTask的子類進行處理。

2.AsyncTask的核心方法

onPreExecute()

這個方法會在 後台任務開始執行之間調用,在主線程執行。 用於進行一些界面上的初始化操作,比如顯示一個進度條對話框等。

doInBackground(Params...)

這個方法中的所有代碼都會 在子線程中運行,我們應該在這里去處理所有的耗時任務。

任務一旦完成就可以通過return語句來將任務的執行結果進行返回,如果AsyncTask的第三個泛型參數指定的是Void,就可以不返回任務執行結果。 注意,在這個方法中是不可以進行UI操作的,如果需要更新UI元素,比如說反饋當前任務的執行進度,可以調用publishProgress(Progress...)方法來完成。

onProgressUpdate(Progress...)

當在後台任務中調用了publishProgress(Progress...)方法後,這個方法就很快會被調用,方法中攜帶的參數就是在後台任務中傳遞過來的。 在這個方法中可以對UI進行操作,在主線程中進行,利用參數中的數值就可以對界面元素進行相應的更新。

onPostExecute(Result)

當doInBackground(Params...)執行完畢並通過return語句進行返回時,這個方法就很快會被調用。返回的數據會作為參數傳遞到此方法中, 可以利用返回的數據來進行一些UI操作,在主線程中進行,比如說提醒任務執行的結果,以及關閉掉進度條對話框等。

上面幾個方法的調用順序:

onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute()

如果不需要執行更新進度則為onPreExecute() --> doInBackground() --> onPostExecute(),

除了上面四個方法,AsyncTask還提供了onCancelled()方法, 它同樣在主線程中執行,當非同步任務取消時,onCancelled()會被調用,這個時候onPostExecute()則不會被調用 ,但是要注意的是, AsyncTask中的cancel()方法並不是真正去取消任務,只是設置這個任務為取消狀態,我們需要在doInBackground()判斷終止任務。就好比想要終止一個線程,調用interrupt()方法,只是進行標記為中斷,需要在線程內部進行標記判斷然後中斷線程。

3.AsyncTask的簡單使用

這里我們模擬了一個下載任務,在doInBackground()方法中去執行具體的下載邏輯,在onProgressUpdate()方法中顯示當前的下載進度,在onPostExecute()方法中來提示任務的執行結果。如果想要啟動這個任務,只需要簡單地調用以下代碼即可:

4.使用AsyncTask的注意事項

①非同步任務的實例必須在UI線程中創建,即AsyncTask對象必須在UI線程中創建。

②execute(Params... params)方法必須在UI線程中調用。

③不要手動調用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)這幾個方法。

④不能在doInBackground(Params... params)中更改UI組件的信息。

⑤一個任務實例只能執行一次,如果執行第二次將會拋出異常。

先從初始化一個AsyncTask時,調用的構造函數開始分析。

這段代碼雖然看起來有點長,但實際上並沒有任何具體的邏輯會得到執行,只是初始化了兩個變數,mWorker和mFuture,並在初始化mFuture的時候將mWorker作為參數傳入。mWorker是一個Callable對象,mFuture是一個FutureTask對象,這兩個變數會暫時保存在內存中,稍後才會用到它們。 FutureTask實現了Runnable介面,關於這部分內容可以看這篇文章。

mWorker中的call()方法執行了耗時操作,即result = doInBackground(mParams);,然後把執行得到的結果通過postResult(result);,傳遞給內部的Handler跳轉到主線程中。在這里這是實例化了兩個變數,並沒有開啟執行任務。

那麼mFuture對象是怎麼載入到線程池中,進行執行的呢?

接著如果想要啟動某一個任務,就需要調用該任務的execute()方法,因此現在我們來看一看execute()方法的源碼,如下所示:

調用了executeOnExecutor()方法,具體執行邏輯在這個方法裡面:

可以 看出,先執行了onPreExecute()方法,然後具體執行耗時任務是在exec.execute(mFuture),把構造函數中實例化的mFuture傳遞進去了。

exec具體是什麼?

從上面可以看出具體是sDefaultExecutor,再追溯看到是SerialExecutor類,具體源碼如下:

終於追溯到了調用了SerialExecutor 類的execute方法。SerialExecutor 是個靜態內部類,是所有實例化的AsyncTask對象公有的,SerialExecutor 內部維持了一個隊列,通過鎖使得該隊列保證AsyncTask中的任務是串列執行的,即多個任務需要一個個加到該隊列中,然後執行完隊列頭部的再執行下一個,以此類推。

在這個方法中,有兩個主要步驟。

①向隊列中加入一個新的任務,即之前實例化後的mFuture對象。

②調用 scheleNext()方法,調用THREAD_POOL_EXECUTOR執行隊列頭部的任務。

由此可見SerialExecutor 類僅僅為了保持任務執行是串列的,實際執行交給了THREAD_POOL_EXECUTOR。

THREAD_POOL_EXECUTOR又是什麼?

實際是個線程池,開啟了一定數量的核心線程和工作線程。然後調用線程池的execute()方法。執行具體的耗時任務,即開頭構造函數中mWorker中call()方法的內容。先執行完doInBackground()方法,又執行postResult()方法,下面看該方法的具體內容:

該方法向Handler對象發送了一個消息,下面具體看AsyncTask中實例化的Hanlder對象的源碼:

在InternalHandler 中,如果收到的消息是MESSAGE_POST_RESULT,即執行完了doInBackground()方法並傳遞結果,那麼就調用finish()方法。

如果任務已經取消了,回調onCancelled()方法,否則回調 onPostExecute()方法。

如果收到的消息是MESSAGE_POST_PROGRESS,回調onProgressUpdate()方法,更新進度。

InternalHandler是一個靜態類,為了能夠將執行環境切換到主線程,因此這個類必須在主線程中進行載入。所以變相要求AsyncTask的類必須在主線程中進行載入。

到此為止,從任務執行的開始到結束都從源碼分析完了。

AsyncTask的串列和並行

從上述源碼分析中分析得到,默認情況下AsyncTask的執行效果是串列的,因為有了SerialExecutor類來維持保證隊列的串列。如果想使用並行執行任務,那麼可以直接跳過SerialExecutor類,使用executeOnExecutor()來執行任務。

四、AsyncTask使用不當的後果

1.)生命周期

AsyncTask不與任何組件綁定生命周期,所以在Activity/或者Fragment中創建執行AsyncTask時,最好在Activity/Fragment的onDestory()調用 cancel(boolean);

2.)內存泄漏

3.) 結果丟失

屏幕旋轉或Activity在後台被系統殺掉等情況會導致Activity的重新創建,之前運行的AsyncTask(非靜態的內部類)會持有一個之前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將不再生效。

自己是從事了七年開發的Android工程師,不少人私下問我,2019年Android進階該怎麼學,方法有沒有?

沒錯,年初我花了一個多月的時間整理出來的學習資料,希望能幫助那些想進階提升Android開發,卻又不知道怎麼進階學習的朋友。【 包括高級UI、性能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的復習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。

㈡ 有哪些 Android 的開源界面庫

比較火爆的Android開源庫有以下:
1、volley
主要有以下模塊:

(1) JSON,圖像等的非同步下載;
(2) 網路請求的排序(scheling)
(3) 網路請求的優先順序處理
(4) 緩存
(5) 多級別取消請求
(6) 和Activity和生命周期的聯動(Activity結束時同時取消所有網路請求)2、android-async-http
主要有以下模塊:
(1) 在匿名回調中處理請求結果
(2) 在UI線程外進行

(3) 文件斷點上傳
(4) 智能重試
(5) 默認gzip壓縮
(6) 支持解析成Json格式
(7) 可將Cookies持久化到SharedPreferences 3、Afinal框架
主要有四大模塊:
(1) 資料庫模塊:android中的
,使用了線程池對sqlite進行操作。
(2) 註解模塊:android中的ioc框架,完全註解方式就可以進行UI綁定和事件綁定。無需findViewById和setClickListener等。
(3) 網路模塊:通過httpclient進行封裝http數據請求,支持ajax方式載入,支持下載、上傳文件功能。
(4) 圖片緩存模塊:通過FinalBitmap,imageview載入bitmap的時候無需考慮bitmap載入過程中出現的oom和android容器快速滑動時候出現的圖片錯位等現象。4、xUtils框架
主要有四大模塊:
(1) 資料庫模塊:android中的
,一行代碼就可以進行增刪改查;
(2) 註解模塊:android中的ioc框架,完全註解方式就可以進行UI,資源和事件綁定;
(3) 網路模塊:支持同步,非同步方式的請求;
(4) 圖片緩存模塊:載入bitmap的時候無需考慮bitmap載入過程中出現的oom和android容器快速滑動時候出現的圖片錯位等現象;5、ThinkAndroid主要有以下模塊:(1) MVC模塊:實現視圖與模型的分離。
(2) ioc模塊:android中的ioc模塊,完全註解方式就可以進行UI綁定、res中的資源的讀取、以及對象的初始化。
(3) 資料庫模塊:android中的
,使用了線程池對sqlite進行操作。
(4) http模塊:通過httpclient進行封裝http數據請求,支持非同步及同步方式載入。
(5) 緩存模塊:通過簡單的配置及設計可以很好的實現緩存,對緩存可以隨意的配置
(6) 圖片緩存模塊:imageview載入圖片的時候無需考慮圖片載入過程中出現的oom和android容器快速滑動時候出現的圖片錯位等現象。
(7) 配置器模塊:可以對簡易的實現配對配置的操作,目前配置文件可以支持Preference、Properties對配置進行存取。
(8) 日誌列印模塊:可以較快的輕易的是實現日誌列印,支持日誌列印的擴展,目前支持對sdcard寫入本地列印、以及控制台列印
(9) 下載器模塊:可以簡單的實現
、後台下載、
、對下載進行控制、如開始、暫停、刪除等等。
(10) 網路狀態檢測模塊:當網路狀態改變時,對其進行檢6、LoonAndroid 主要有以下模塊:
(1) 自動注入框架(只需要繼承框架內的application既可)
(2) 圖片載入框架(多重緩存,自動回收,最大限度保證內存的安全性)
(3) 網路請求模塊(繼承了基本上現在所有的

(4) eventbus(集成一個開源的框架)
(5) 驗證框架(集成開源框架)
(6) json解析(支持解析成集合或者對象)
(7) 資料庫(不知道是哪位寫的 忘記了)
(8) 多線程斷點下載(自動判斷是否支持多線程,判斷是否是重定向)
(9) 自動更新模塊
(10) 一系列工具類

㈢ Android中的線程和線程池

一、除了Thread外,扮演線程角色的還有:AsyncTask和IntentService,同時HandlerThread也扮演特殊的線程。

      IntentService:內部採用HandlerThread來執行,像一個後台線程,同時是一個服務,不容易被系統殺死。

二、HandlerThread的run方法是一個無限循環

三、IntentService中任務是排隊執行的

四、AsyncTask 

1、Android1.6之前串悄段桐行執行任務,1.6時候採用線程池裡的並行,Android3.0開始又開始串列(為了避免並發錯誤),單任可以並行。

2、AsyncTask必須在UI線程調用(不過這個不是絕對的,和版本有關燃腔系,API 16之前,API 16到 22, API 22以後) 參考一

原因:內部有靜態Handler,採用UI線程的Looper來處理消息,這就是為什麼AsyncTask必須在UI線程調用,因為子線程默認沒有Looper無法創建下面的Handler,程序會直接Crash

3、AsyncTask中有兩個線程池和一個Handler,一個線程池用啟坦於任務排隊,一個線程池用於真正的執行任務,InternalHandler用於將

執行環境從線程池切換到主線程

AsyncTask串列與並行

五、線程池

線程池中多餘的線程是如何回收的

㈣ Android IPC機制(三):淺談Binder的使用

在探討Android IPC機制中,尤其是關注於Binder的使用時,我們首先需要理解AIDL(Android Interface Definition Language)作為實現跨進程通訊的基礎。實際上,AIDL的實現是建立在Binder機制之上的。本文將圍繞如何使用AIDL來利用Binder進行進程間通訊,進行深入的剖析與解答。

開始於構建IMyAidl.aidl介面文件,通過AIDL工具編譯生成了對應的.java文件,這部分主要為實現介面的結構和方法定義。在生成的文件中,可以看到,介面繼承自IInterface,並包含了一個靜態內部抽象類Stub,該類繼承自Binder且實現了所定義的介面,從而實現了介面方法的邏輯。

深入分析Stub類,其構造方法調用了Binder的attachInterface方法,將介面與Binder進行關聯,並通過傳遞DESCRIPTOR參數來唯一標識當前介面。接著,asInterface方法通過檢查傳入的IBinder對象的有效性,並嘗試獲取與當前介面相關的方法,實現客戶端與服務端的介面綁定。當客戶端與服務端處於同一進程時,返回Stub對象本身;反之,返回一個Proxy代理類對象,以此實現代理機制,允許客戶端在不同進程間調用服務端介面方法。

此外,asBinder方法返回當前對象的Binder引用,而onTransact方法則在服務端的Binder線程池中執行遠程請求處理。當客戶端調用addPerson或getPersonList方法時,請求會被轉化為Parcel對象,並通過Transact調用傳遞至服務端。服務端接收到請求後,調用實現的方法進行處理,並將結果返回給客戶端,整個過程實現跨進程通訊。

至於優化方面,AIDL的實現中存在線程阻塞的風險,尤其是在UI線程發送請求時。為避免此問題,建議在子線程中發送非同步請求,以防止ANR(應用程序無響應)的發生。同時,考慮到Binder可能意外斷開的情況,應實現重新連接服務的機制。這可以通過為Binder設置DeathRecipient監聽器或在onServiceDisconnected方法中重連服務來實現,確保通訊的穩定性和可靠性。

綜上所述,AIDL作為Android進程間通訊的一種方式,其核心在於利用Binder機制實現跨進程介面綁定與方法調用。通過理解並應用上述原理與優化策略,開發者能夠更高效地構建和維護Android應用中的進程間通訊邏輯,確保系統的穩定性和用戶體驗。

㈤ android啟動後怎麼查看其裡面的進程和線程

1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。

3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)

一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。

Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。

原文地址:Android中的進程與線程 原文作者:江鵬

當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:

1、進程

組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。

所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。

public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。

參數

keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象

返回值

如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。

當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。

當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。

2、線程

雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。

線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。

Looper類

該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:

1. Android中進程與進程、線程與線程之間如何通信?
1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。

3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)

一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。

Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。

原文地址:Android中的進程與線程 原文作者:江鵬

當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:

1、進程

組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。

所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。

public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。

參數

keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象

返回值

如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。

當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。

當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。

2、線程

雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。

線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。

Looper類

該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:

2.1、遠程過程調用(Remote procere calls,RPCs)

Android有一個輕量級的遠程過程調用機制——方法在本地調用卻在遠程(另外一個進程中)執行,結果返回給調用者。這需要將方法調用和它伴隨的數據分解為操作系統能夠理解的層次,從本地進程和地址空間傳輸到遠程進程和地址空間,並重新組裝調用。返回值以相反方向傳輸。Android提供了做這些工作的所有代碼,這樣我們可以專注於定義和執行RPC介面本身。

一個RPC介面僅包含方法。所有的方法同步地執行(本地方法阻塞直到遠程方法執行完成),即使是沒有返回值。簡言之,該機制工作原理如下:首先,你用簡單的IDL(interface definition language,介面定義語言)聲明一個你想實現的RPC介面。從這個聲明中,aidl工具生成一個Java介面定義,提供給本地和遠程進程。它包含兩個內部類,如下圖所示:

內部類有管理你用IDL定義的介面的遠程過程調用所需要的所有代碼。這兩個內部類都實現了IBinder介面。其中之一就是在本地由系統內部使用,你寫代碼可以忽略它。另外一個是Stub,擴展自Binder類。除了用於有效地IPC(interprocess communication)調用的內部代碼,內部類在RPC介面聲明中還包含方法聲明。你可以定義Stub的子類實現這些方法,如圖中所示。

通常情況下,遠程過程有一個服務管理(因為服務能通知系統關於進程和它連接的其它進程的信息)。它有由aidl工具生成的介面文件和Stub子類實現的RPC方法。服務的客戶端僅有由aidl工具生成的介面文件。

下面介紹服務如何與它的客戶端建立連接:

· 服務的客戶端(在本地端的)應該實現onServiceConnected() 和onServiceDisconnected() 方法,因此當與遠程服務建立連接成功和斷開連接是會通知它。然後調用bindService() 建立連接。

· 服務的onBind()方法將實現為接受或拒絕連接,者取決於它接受到的意圖(該意圖傳送到binServive())。如果連接被接受,它返回一個Stub子類的實例。

· 如果服務接受連接,Android調用客戶端的onServiceConnected()方法且傳遞給它一個IBinder對象,返回由服務管理的Stub子類的一個代理。通過代理,客戶端可以調用遠程服務。

這里只是簡單地描述,省略了一些RPC機制的細節。你可以查閱相關資料或繼續關注Android開發之旅,後面將為你奉上。

2.2、線程安全方法

在一些情況下,你實現的方法可能會被不止一個線程調用,因此必須寫成線程安全的。這對遠程調用方法是正確的——如上一節討論的RPC機制。當從IBinder進程中調用一個IBinder對象中實現的一個方法,這個方法在調用者的線程中執行。然而,當從別的進程中調用,方法將在Android維護的IBinder進程中的線程池中選擇一個執行,它不在進程的主線程中執行。例如,一個服務的onBind()方法在服務進程的主線程中被調用,在onBind()返回的對象中執行的方法(例如,實現RPC方法的Stub子類)將在線程池中被調用。由於服務可以有一個以上的客戶端,所以同時可以有一個以上的線程在執行同一個IBinder方法。因此,IBinder的方法必須是線程安全的。

同樣,一個內容提供者可以接受其它進程產生的數據請求。雖然ContentResolver 和 ContentProvider 類隱藏進程通信如何管理的,對應哪些請求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在內容提供者的進程的線程池中被調用,而不是在這一進程的主線程中。因為這些方法可以同時從任意數量的線程中調用,他們也必須實現為線程安全的。

閱讀全文

與android線程池工具相關的資料

熱點內容
抖音獨立電商app是什麼意思 瀏覽:808
公司晨會解壓小游戲 瀏覽:340
怎麼加密成摩斯密碼 瀏覽:665
流體機械pdf 瀏覽:187
編譯器管理的存儲cache 瀏覽:181
自行車維修pdf 瀏覽:532
霸道王子的絕對命令漫畫免費 瀏覽:886
netbeans81php 瀏覽:273
javathreadstop 瀏覽:307
域名解析分發源碼免費 瀏覽:851
百戰程序員教學視頻 瀏覽:626
上海演算法模型人工智慧零基礎培訓 瀏覽:672
安卓90什麼時候會普及 瀏覽:182
小學點點之間線的演算法 瀏覽:100
程序員編碼定律 瀏覽:980
伺服器怎麼創建節點 瀏覽:766
手機通訊錄加密可以改嗎 瀏覽:131
ivf源代碼編譯 瀏覽:886
怎麼樣把手機桌面設置成文件夾 瀏覽:469
單片機項目課題 瀏覽:507