當應用程式的元件第一次運作時,Android将啟動一個隻有一個執行線程的Linux程序。預設,應用程式所有的元件運作在這個程序和線程中。然而,你可以安排元件運作在其他程序中,且你可以為程序衍生出其它線程。本文從下面幾點來介紹Android的程序與線程:
1、程序
2、線程
2.1、遠端過程調用(Remote procedure calls,RPCs)
2.2、線程安全方法
元件運作于哪個程序中由清單檔案控制。元件元素——<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會權衡他們對使用者重要性的相對權值。例如,與運作在螢幕可見的活動程序相比(前台程序),它更容易關閉一個程序,它的活動在螢幕是不可見(背景程序)。決定是否終結程序,取決于運作在程序中的元件狀态。關于元件的狀态,将在後面一篇——元件生命周期中介紹。
雖然你可能會将你的應用程式限制在一個程序中,但有時候你會需要衍生一個線程做一些背景工作。因為使用者界面必須很快地響應使用者的操作,是以活動寄宿的線程不應該做一些耗時的操作如網絡下載下傳。任何不可能在短時間完成的操作應該配置設定到别的線程。
線程在代碼中是用标準的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請參閱相關資料。
Android有一個輕量級的遠端過程調用機制——方法在本地調用卻在遠端(另外一個程序中)執行,結果傳回給調用者。這需要将方法調用和它伴随的資料分解為作業系統能夠了解的層次,從本地程序和位址空間傳輸到遠端程序和位址空間,并重新組裝調用。傳回值以相反方向傳輸。Android提供了做這些工作的所有代碼,這樣我們可以專注于定義和執行RPC接口本身。
一個RPC接口僅包含方法。所有的方法同步地執行(本地方法阻塞直到遠端方法執行完成),即使是沒有傳回值。簡言之,該機制工作原理如下:首先,你用簡單的IDL(interface definition language,接口定義語言)聲明一個你想實作的RPC接口。從這個聲明中,aidl工具生成一個Java接口定義,提供給本地和遠端程序。它包含兩個内部類,如下圖所示:
<a target="_blank" href="http://blog.51cto.com/attachment/201008/101143121.png"></a>
内部類有管理你用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開發之旅,後面将為你奉上。
在一些情況下,你實作的方法可能會被不止一個線程調用,是以必須寫成線程安全的。這對遠端調用方法是正确的——如上一節讨論的RPC機制。當從IBinder程序中調用一個IBinder對象中實作的一個方法,這個方法在調用者的線程中執行。然而,當從别的程序中調用,方法将在Android維護的IBinder程序中的線程池中選擇一個執行,它不在程序的主線程中執行。例如,一個服務的onBind()方法在服務程序的主線程中被調用,在onBind()傳回的對象中執行的方法(例如,實作RPC方法的Stub子類)将線上程池中被調用。由于服務可以有一個以上的用戶端,是以同時可以有一個以上的線程在執行同一個IBinder方法。是以,IBinder的方法必須是線程安全的。
同樣,一個内容提供者可以接受其它程序産生的資料請求。雖然ContentResolver 和 ContentProvider 類隐藏程序通信如何管理的,對應哪些請求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在内容提供者的程序的線程池中被調用,而不是在這一程序的主線程中。因為這些方法可以同時從任意數量的線程中調用,他們也必須實作為線程安全的。
本系列的其它文章:
<a href="http://skynet.blog.51cto.com/1943397/365407" target="_blank">Android 開發之旅:環境搭建及HelloWorld</a>
<a href="http://skynet.blog.51cto.com/1943397/365402" target="_blank">Android 開發之旅:HelloWorld項目的目錄結構</a>
<a href="http://skynet.blog.51cto.com/1943397/365394" target="_blank">Android 開發之旅:android架構</a>
<a href="http://skynet.blog.51cto.com/1943397/365392" target="_blank">Android 開發之旅:應用程式基礎及元件</a>
<a href="http://skynet.blog.51cto.com/1943397/365389" target="_blank">Android 開發之旅:應用程式基礎及元件(續)</a>
<a href="http://skynet.blog.51cto.com/1943397/365383" target="_blank">Android 開發之旅:活動與任務</a>
從android架構到這篇基本内容都是意譯自Android SDK文檔。
本文轉自Saylor87 51CTO部落格,原文連結:http://blog.51cto.com/skynet/365379,如需轉載請自行聯系原作者