Android開發之旅:程式與執行緒

技術小胖子發表於2017-11-02

引言

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

  1. 1、程式
  2. 2、執行緒
    1. 2.1、遠端過程呼叫(Remote procedure calls,RPCs)
    2. 2.2、執行緒安全方法

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. class LooperThread extends Thread {   
  2.       public Handler mHandler;   
  3.         
  4.       public void run() {   
  5.           Looper.prepare();   
  6.             
  7.           mHandler = new Handler() {   
  8.               public void handleMessage(Message msg) {   
  9.                   // process incoming messages here   
  10.               }   
  11.           };   
  12.             
  13.           Looper.loop();   
  14.       }   
  15.  }  

 

更多的關於Looper的資訊及Handler、HandlerThread請參閱相關資料。

2.1、遠端過程呼叫(Remote procedure calls,RPCs)

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

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

Android開發之旅:程式與執行緒

內部類有管理你用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(),在內容提供者的程式的執行緒池中被呼叫,而不是在這一程式的主執行緒中。因為這些方法可以同時從任意數量的執行緒中呼叫,他們也必須實現為執行緒安全的。

本系列的其它文章:

  1. Android 開發之旅:環境搭建及HelloWorld
  2. Android 開發之旅:HelloWorld專案的目錄結構
  3. Android 開發之旅:android架構
  4. Android 開發之旅:應用程式基礎及元件
  5. Android 開發之旅:應用程式基礎及元件(續)
  6. Android 開發之旅:活動與任務
  7. 從android架構到這篇基本內容都是意譯自Android SDK文件。



     本文轉自Saylor87 51CTO部落格,原文連結:http://blog.51cto.com/skynet/365379,如需轉載請自行聯絡原作者




相關文章