原文地址: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 thread)被阻塞,
導致程式出現ANR.
4,android單線程模式:androidUI操作並不是安全執行緒的並且這些操作必須在UI線程中執行,
如果子線程中直接去使用,會造成異常.
一個activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個activity,
其就是在同一個線程中?那從一個activity跳轉到另一個activity時,是不是跳出的那個activity就出在
睡眠狀態?
每個activity都有一個process屬性,可以指定該activity是屬於哪個進程的,當然如果不明確指明,
應該就是從屬性預設進程(application指定的,如果未指定,應該就是預設主進程).
android中有task的概念,而同一個task的各個activity會形成一個棧,只有站定的activity才有機會
與使用者互動.
當應用程式的組件第一次運行時,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互動:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
更多的關於Looper的資訊及Handler、HandlerThread請參閱相關資料。
2.1、遠端程序呼叫(Remote procedure 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(),在內容提供者的進程的線程池中被調用,而不是在這一進程的主線程中。因為這些方法可以同時從任意數量的線程中調用,他們也必須實現為安全執行緒的。