|
1. Android中進程與進程、線程與線程之間如何通信?
1)一個 Android 程序開始運行時,會單獨啟動一個Process。 默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。 默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。 2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創(chuàng)建。該線程主要負責UI界面的顯示、更新和控件交互,所以又叫UI Thread。 3)一個Android程序創(chuàng)建之初,一個Process呈現(xiàn)的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所 以,MainThread所調(diào)用的每一個函數(shù),其耗時應該越短越好,而對于比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程 序出現(xiàn)ANR(Application not response) 一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態(tài)了? 【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬于哪個進程的。當然如果不明確指明,應該就是從屬于默認進程(Application指定的,如其未指定,應該就是默認主進程)。 Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。 原文地址:Android中的進程與線程 原文作者:江鵬 當應用程序的組件第一次運行時,Android將啟動一個只有一個執(zhí)行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程: 1、進程 組件運行于哪個進程中由清單文件控制。組件元素—— <activity>、<service>、<receiver>、<provider>,都有一個 process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以 設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的權 限。<application>元素也有process屬性,為所有的組件設置一個默認值。 所有的組件都在特定進程的主線程中實例化,且系統(tǒng)調(diào)用組件是由主線程派遣。不會為每個實例創(chuàng)建單獨的線程,因此,對應這些調(diào)用的方法——諸如 View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統(tǒng)調(diào)用時應該執(zhí)行很長時間或阻塞 操作(如網(wǎng)絡操作或循環(huán)計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。 public boolean onKeyDown(int keyCode,KeyEvent event):默認實現(xiàn)KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或 KEYCODE_ENTER然后釋放時執(zhí)行,如果視圖可用且可點擊。 參數(shù) keyCode-表示按鈕被按下的鍵碼,來自KeyEvent event-定義了按鈕動作的KeyEvent對象 返回值 如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。 當內(nèi)存剩余較小且其它進程請求較大內(nèi)存并需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。 當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前臺進程),它更容易關閉一個 進程,它的活動在屏幕是不可見(后臺進程)。決定是否終結進程,取決于運行在進程中的組件狀態(tài)。關于組件的狀態(tài),將在后面一篇——組件生命周期中介紹。 2、線程 雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些后臺工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網(wǎng)絡下載。任何不可能在短時間完成的操作應該分配到別的線程。 線程在代碼中是用標準的Java線程對象創(chuàng)建的,Android提供了一些方便的類來管理線程——Looper用于在線程中運行消息循環(huán)、Handler用戶處理消息、HandlerThread用戶設置一個消息循環(huán)的線程。 Looper類 該類用戶在線程中運行消息循環(huán)。線程默認沒有消息循環(huán),可以在線程中調(diào)用prepare()創(chuàng)建一個運行循環(huán);然后調(diào)用loop()處理消息直到 循環(huán)結束。大部分消息循環(huán)交互是通過Handler類。下面是一個典型的執(zhí)行一個Looper線程的例子,分別使用prepare()和loop()創(chuàng)建 一個初始的Handler與Looper交互: 1. Android中進程與進程、線程與線程之間如何通信? 1)一個 Android 程序開始運行時,會單獨啟動一個Process。 默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。 默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。 2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創(chuàng)建。該線程主要負責UI界面的顯示、更新和控件交互,所以又叫UI Thread。 3)一個Android程序創(chuàng)建之初,一個Process呈現(xiàn)的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所 以,MainThread所調(diào)用的每一個函數(shù),其耗時應該越短越好,而對于比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程 序出現(xiàn)ANR(Application not response) 一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態(tài)了? 【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬于哪個進程的。當然如果不明確指明,應該就是從屬于默認進程(Application指定的,如其未指定,應該就是默認主進程)。 Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。 原文地址:Android中的進程與線程 原文作者:江鵬 當應用程序的組件第一次運行時,Android將啟動一個只有一個執(zhí)行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程: 1、進程 組件運行于哪個進程中由清單文件控制。組件元素—— <activity>、<service>、<receiver>、<provider>,都有一個 process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以 設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的權 限。<application>元素也有process屬性,為所有的組件設置一個默認值。 所有的組件都在特定進程的主線程中實例化,且系統(tǒng)調(diào)用組件是由主線程派遣。不會為每個實例創(chuàng)建單獨的線程,因此,對應這些調(diào)用的方法——諸如 View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統(tǒng)調(diào)用時應該執(zhí)行很長時間或阻塞 操作(如網(wǎng)絡操作或循環(huán)計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。 public boolean onKeyDown(int keyCode,KeyEvent event):默認實現(xiàn)KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或 KEYCODE_ENTER然后釋放時執(zhí)行,如果視圖可用且可點擊。 參數(shù) keyCode-表示按鈕被按下的鍵碼,來自KeyEvent event-定義了按鈕動作的KeyEvent對象 返回值 如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。 當內(nèi)存剩余較小且其它進程請求較大內(nèi)存并需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。 當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前臺進程),它更容易關閉一個 進程,它的活動在屏幕是不可見(后臺進程)。決定是否終結進程,取決于運行在進程中的組件狀態(tài)。關于組件的狀態(tài),將在后面一篇——組件生命周期中介紹。 2、線程 雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些后臺工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網(wǎng)絡下載。任何不可能在短時間完成的操作應該分配到別的線程。 線程在代碼中是用標準的Java線程對象創(chuàng)建的,Android提供了一些方便的類來管理線程——Looper用于在線程中運行消息循環(huán)、Handler用戶處理消息、HandlerThread用戶設置一個消息循環(huán)的線程。 Looper類 該類用戶在線程中運行消息循環(huán)。線程默認沒有消息循環(huán),可以在線程中調(diào)用prepare()創(chuàng)建一個運行循環(huán);然后調(diào)用loop()處理消息直到 循環(huán)結束。大部分消息循環(huán)交互是通過Handler類。下面是一個典型的執(zhí)行一個Looper線程的例子,分別使用prepare()和loop()創(chuàng)建 一個初始的Handler與Looper交互: 2.1、遠程過程調(diào)用(Remote procedure calls,RPCs) Android有一個輕量級的遠程過程調(diào)用機制——方法在本地調(diào)用卻在遠程(另外一個進程中)執(zhí)行,結果返回給調(diào)用者。這需要將方法調(diào)用和它伴隨 的數(shù)據(jù)分解為操作系統(tǒng)能夠理解的層次,從本地進程和地址空間傳輸?shù)竭h程進程和地址空間,并重新組裝調(diào)用。返回值以相反方向傳輸。Android提供了做這 些工作的所有代碼,這樣我們可以專注于定義和執(zhí)行RPC接口本身。 一個RPC接口僅包含方法。所有的方法同步地執(zhí)行(本地方法阻塞直到遠程方法執(zhí)行完成),即使是沒有返回值。簡言之,該機制工作原理如下:首先, 你用簡單的IDL(interface definition language,接口定義語言)聲明一個你想實現(xiàn)的RPC接口。從這個聲明中,aidl工具生成一個Java接口定義,提供給本地和遠程進程。它包含兩 個內(nèi)部類,如下圖所示: 內(nèi)部類有管理你用IDL定義的接口的遠程過程調(diào)用所需要的所有代碼。這兩個內(nèi)部類都實現(xiàn)了IBinder接口。其中之一就是在本地由系統(tǒng)內(nèi)部使 用,你寫代碼可以忽略它。另外一個是Stub,擴展自Binder類。除了用于有效地IPC(interprocess communication)調(diào)用的內(nèi)部代碼,內(nèi)部類在RPC接口聲明中還包含方法聲明。你可以定義Stub的子類實現(xiàn)這些方法,如圖中所示。 通常情況下,遠程過程有一個服務管理(因為服務能通知系統(tǒng)關于進程和它連接的其它進程的信息)。它有由aidl工具生成的接口文件和Stub子類實現(xiàn)的RPC方法。服務的客戶端僅有由aidl工具生成的接口文件。 下面介紹服務如何與它的客戶端建立連接: · 服務的客戶端(在本地端的)應該實現(xiàn)onServiceConnected() 和onServiceDisconnected() 方法,因此當與遠程服務建立連接成功和斷開連接是會通知它。然后調(diào)用bindService() 建立連接。 · 服務的onBind()方法將實現(xiàn)為接受或拒絕連接,者取決于它接受到的意圖(該意圖傳送到binServive())。如果連接被接受,它返回一個Stub子類的實例。 · 如果服務接受連接,Android調(diào)用客戶端的onServiceConnected()方法且傳遞給它一個IBinder對象,返回由服務管理的Stub子類的一個代理。通過代理,客戶端可以調(diào)用遠程服務。 這里只是簡單地描述,省略了一些RPC機制的細節(jié)。你可以查閱相關資料或繼續(xù)關注Android開發(fā)之旅,后面將為你奉上。 2.2、線程安全方法 在一些情況下,你實現(xiàn)的方法可能會被不止一個線程調(diào)用,因此必須寫成線程安全的。這對遠程調(diào)用方法是正確的——如上一節(jié)討論的RPC機制。當從 IBinder進程中調(diào)用一個IBinder對象中實現(xiàn)的一個方法,這個方法在調(diào)用者的線程中執(zhí)行。然而,當從別的進程中調(diào)用,方法將在Android維 護的IBinder進程中的線程池中選擇一個執(zhí)行,它不在進程的主線程中執(zhí)行。例如,一個服務的onBind()方法在服務進程的主線程中被調(diào)用,在 onBind()返回的對象中執(zhí)行的方法(例如,實現(xiàn)RPC方法的Stub子類)將在線程池中被調(diào)用。由于服務可以有一個以上的客戶端,所以同時可以有一 個以上的線程在執(zhí)行同一個IBinder方法。因此,IBinder的方法必須是線程安全的。 同樣,一個內(nèi)容提供者可以接受其它進程產(chǎn)生的數(shù)據(jù)請求。雖然ContentResolver 和 ContentProvider 類隱藏進程通信如何管理的,對應哪些請求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在內(nèi)容提供者的進程的線程池中被調(diào)用,而不是在這 一進程的主線程中。因為這些方法可以同時從任意數(shù)量的線程中調(diào)用,他們也必須實現(xiàn)為線程安全的。 |
|
|