Android程序模塊2

4、Intent
Intent   是對被執行操作的抽象描述。調用startActivity(Intent),可以啓動 Activity;調用broadcastIntent(Intent),可以把Intent 發送給任何相關的
IntentReceiver 組件;調用startService(Intent, Bundle) 以及bindService(Intent, String, ServiceConnection, int)    可以讓應用和後臺服務進行通信。
Intent    提供了一個在不同應用的代碼之間進行動態綁定(late runtime binding) 的機制。它主要被用來啓動Activities,因此可以被看作是Activities之間的粘合劑。Intent 大體上是一個被動數據結構,該數據結構包括被執行動作的抽象描述。Intent 中的主要內容有:
action --    需要被執行的動作。比如VIEW_ACTION, EDIT_ACTION, MAIN_ACTION 等。
data --    執行動作要操作的數據,在Intent 裏用指向數據記錄的URI (ContentURI) 表示。比如聯繫人數據庫中的一個聯繫人記錄。

  除了action, data 兩個主要屬性,Intent 還具有一些其它屬性,這些屬性也可以被用在Intent    裏:
category --    類別,被執行動作的附加信息。例如LAUNCHER_CATEGORY 表示Intent    的接受者應該在Launcher    中作爲頂級應用出現;而ALTERNATIVE_CATEGORY 表示當前的Intent    是一系列的可選動作中的一個,這些動作可以在同一塊數據上執行。
type --    數據類型,顯式指定Intent    的數據類型(MIME)   。一般上Intent 的數據類型能夠根據數據本身進行判定,但是通過設置這個屬性,可以強制採用顯式指定的類型而不 再進行推導。
component --    組件,爲使用Intent    的組件類指定名稱。通常會根據Intent 中包含的其它信息 比如action, data/type, categories —— 進行查找,最終找到一個與之匹配的組件。如果這個屬性存在的話,將直接使用它指定的組件,不再執行上述查找過程。指定了這個屬性以後,Intent    的其它所有屬性都是可選的。
extras --    額外的附加信息,是其它所有附加信息的集合。使用extras 可以爲組件提“ ” 供擴展信息,比如,如果要發送電子郵件,也就是要執行 發送電子郵件 的動作,可以將電子郵件的標題、正文等保存在extras    裏。在Intent類裏定義了多種標準action和category 常量(字符串),同時應用也可以根據自己的需要進行定義。
Intent    有兩種主要形式:
顯式意圖:
顯式意圖是指定了 component   屬 性的 intents 。 調 用 setComponent(ComponentName)    或者setClass(Context, Class)    可以爲intents 設定component   ——    屬性 指定具體的組件類。這些intents 一般不包括其它任何信息,它們通常只是用來通知應用啓動內部的activities    作爲該應用的(當前)用戶界面。
隱式意圖:
       隱式意圖是沒有指明comonent    的intents   。這些intents 必須包括足夠的信息,這樣系統才能確定在所有的可用組件中,對一個intent    來說運行哪一個組件纔是最合適的。Intent    解析機制主要是將已安裝應用程序包裏的Intent-Filter    描述和Intent 進行匹配。如果使用廣播發送Intent   ,還要在已經註冊的IntentReceiver 中盡心匹配。更多的相關描述可以在IntentFilter    中找到。
  在解析Intent    的過程中要用到Intent 的三個屬性:動作、數據類型和類別。使用這些屬性,就可以PackageManager    上查詢能夠處理當前intent 的合適組件。組件是否合適 由AndroidManifest.xml    文件中提供的intent    信息決定。判斷的方法如下:
如果intent    指明瞭要執行的action   ,組件action    列表中就必須包含着個action,否則不能匹配;
如果Intent    沒有提供數據類型(type)   ,系統從數據(data) 中得到數據類型。和 action    一樣,組件的數據類型列表中必須包含intent    的數據類型,否則不能匹配。
如果Intent    中的數據不是content:    類型的URL   ,而且Intent 也沒有明確指定它的數據類型,將根據Intent   中數據的scheme (   比如http: or mailto:) 進行匹配。同上,Intent    的scheme    必須出現在組件的scheme    列表中。
如果Intent 指定了一個或多個類別,這些類別必須全部出現在組建的類別列表中。比如 intent   中 包 含 了兩個 類別:LAUNCHER_CATEGORY   和 ALTERNATIVE_CATEGORY   ,解析得到的組件必須至少包含這兩個類別。
5、Service
服務是在後臺長時間運行的應用組件,不和用戶直接進行交互。在每一個服務類在 AndroidManifest.xml     文件中,必須有一個相應的<service> 聲明。服務必須用 
Context.startService()    或者Context.bindService()    啓動。和其它應用對象一樣,服務運行在它們宿主進程的主線程裏。這意味着,如果一個服務 需要執行阻塞操作(比如網絡操作)或者CPU    敏感的操作(比如MP3播放器),它應該 分離出一個線程來執行這樣的操作。服務類是應用程序的生命週期中的一個重要部分。在
這裏要討論的內容有:
  服務的生命週期
  訪問權限
  進程生命週期

服務的生命週期
  啓動服務有兩種方法。
  如果客戶調用Context.startService(),系統將獲得服務(如果服務不存在,系統創建服務,然後調用它的onCreate() 方法),然後使用調用者提供的參數調用服務的 onStart(int,   Bundle)  方 法。 從 此 以 後 ,服 務開始持續運 行 , 直 到 Context.stopService()     或 者 stopSelf()   被 調 用 。注 意: 多次調 用 Context.startService()雖然會導致onStart() 被多次調用,但是服務本身不會嵌套。所 以無論調用多少次Context.startService()   ,只要調用一次Context.stopService() 或者stopSelf()   ,服務就會停止運行。
 客戶也可以調用Context.bindService() 獲得到服務的永久連接。如果服務之前沒有啓動,一樣會創建服務然後調用它的onCreate()    方法;但是不會調用它的onStart() 方 法。服務調用它的getBinder()    方法,並且將返回的IBinder 對象傳遞給客戶。連接建立以後,不管客戶是否保留這個IBinder 對象的引用,只要連接還存在,服務都會持續運行。通常返回的IBinder    對象是一個由AIDL    實現的複雜接口。服務可以同時被啓動和綁定多個連接。在這種情況下,只要服務被啓動,或者存在着到這個服務的連接,服務都會持續運行。當兩個條件都不滿足時,系統調用服務的 onDestroy()    方法,服務從此被終止。當onDestroy() 返回的時候,所有的清理工作(停止線程,取消已經註冊的receivers   )都已經完成。

訪問權限
  對服務的全局訪問權限可以通過服務的manifest    中的<service> 元素指定。這樣,其它應用需要在它們的manifest    中聲明對應的<uses-permission> 元素,這樣才能啓動、停止和綁定到服務。同時,在執行IPC    調用之前,服務可以調用checkCallingPermission(String) 對這次IPC    調用的權限進行檢查。進程生命週期
只要服務被啓動或者被客戶綁定(建立連接),Android 系統就儘可能維護一個進程來作這個服務的宿主。當系統內存不足的時候,系統需要殺死進程來出讓內存。這時候在下列情況下,服務的宿主進程具有較高的優先級:
如果服務已經被啓動,它的宿主進程比任何在屏幕上對用戶可見的進程都具有更低的優先級;但是比其它所有不可見的進程都具有更高的優先級。通常對用戶可見的進程的數量 非常少,所以正在運行的服務在絕大多數時候不會被殺死 除非系統的可用內存極其 匱乏。
如果有客戶綁定在服務上,服務的宿主進程的優先級至少和客戶的優先級一樣(不會 比客戶更低)。這意味着如果客戶對用戶可見,那麼服務本身也會被系統認爲對用戶可見。在服務的宿主進程中運行有其它應用組件,比如activity,可以提高整個進程的優先 級,而不是僅僅提高服務本身的優先級。

6、NotificationManager
NotificationManager用來通知手機使用者有事件發生的類。用來告訴使用者在後臺有一些事情發生了。
這些通知可以採用以下一些不同的方式:
1. 當時間發生時臨時顯示一個View對象。
2. 在狀態欄上顯示一個圖標,並通過圖標能過激活。
3. 打開或閃爍設備上的LED燈或者通過閃爍背光,播放聲音,或者振動提示用戶。

用兩種方式可以在屏幕上顯示一條消息,這個消息會在一段時間內消失:
notifyWithView(int, View, int, Notification)和notifyWithText(int, charSequence, int, Notification);
函數notifyWithText(int, charSequence, int, Notification)方法只是構造一個帶提示文字的TextView對象。這些方法也產生了一個Notification對象,該對
象是你能夠設定一個固定的提示方法和其它的一些屬性。如果要使用一個Intent或狀態欄單獨的提示使用者,可以使用notify()方法。
當提示信息框(View  對象)被顯示給使用者時,是作爲一個浮動在當前應用(application)   之上的View 對象出現的。它永遠不能接受焦點(focus),因爲用戶可能正在
錄入信息或在做其它什麼事情。儘管如此,當仍然顯示你想給用戶所看的信息時,一個好主意是儘量避免唐突。音量控制和短消息到達提示是兩個可以考慮的。
  每一個通知方法都帶一個整型的id    參數。從應用到系統這個id 參數唯一標識了這次通知,因此,在你的應用裏要確保id 唯一。如果你調用一個通知方法,使用當前在用通知 的id    並且傳遞一組新的通知參數,則該通知將被更新。例如,你傳遞一個新的狀態欄圖標,位於狀態欄的原先的圖標將被新的代替。同樣,傳遞同一個id   給cancel(int) 方法將清除該通知。

7、Android IDL
通常每個應用程序都在它自己的進程內運行,但有時需要在進程間傳遞對象,你可以通過應用程序UI的方式寫個運行在一個不同的進程中的service。在AndRoid平臺中,一個進程通常不能訪問其它進程中的內存區域。AIDL爲解決進程間通信提供了一套機制。
AIDL是一個IDL 語言,它可以生成一段代碼,可以使在一個Android設備上運行的兩個進程使用內部通信進程進行交互。如果你需要在一個進程中(例如:在一個Activity中)訪問另一個進程中(例如:一個Service)某個對象的方法,你就可以使用AIDL來生成這樣的代碼來傳遞各種參數。
AIDL IPC的機制是基於接口的,和COM或Corba類似,但它是輕量級的。
下面介紹如何使用AIDL:
1. 創建你的AIDL文件,這個文件定義一個接口(YourInterface.aidl),該接口定義了可供客戶端訪問的方法和屬性。注意AIDL的接口文件有一定的語法規則,但是十分簡單。
2.如果你在Eclipse編寫的話,這是會自動創建一個Java類,就是接口文件自動生成的符合Java   語法規則的接口類。
3   .實現接口方法-AIDL編譯器從你的AIDL接口中使用JAVA編程語言來創建一個接口。這個接口有一個名爲Stub的內部抽象類,它繼承接口(並實現供IPC調用的所必需的幾個附加方法)   。你必須創建一個類來實現該接口。
4   .向客戶端開放接口-如果你寫個service,你應該擴展該Service並重載getBinder()   方法來返回一個實現上述接口的類的實例。

AIDL語法簡單,你可以用來聲明一個帶一個或多個方法的接口,也可以傳遞參數和返回值。這些參數和返回值可以是任何類型,甚至是其它的AIDL生成的接口。然而,值得重視的是你必須導入所有的non-bult-in   類型,即使他們已經作爲接口在其它包裏定義了。

以下代碼是AIDL的一個例子:
package com.google.android.sample;
interface MDSInterface {
void playFile( in int position );
};
AIDL生成一個接口文件,文件名和你的AIDL文件名一致。如果你使用的是Eclipse插件,AIDL會作爲build過程的一部分自動運行。生成的接口包括一個名爲Stub的內部抽象類,該類聲明瞭你在aidl   文件中聲明的所有方法。實現接口,具體代碼如下:
MDSInterface.Stub mBinder = new MDSInterface.Stub() {
void playFile( int position) {
     //To-do sth.
}
};
實現接口時有幾個原則: 
拋出的異常不要返回給調用者。
IPC調用是同步的。如果你知道一個IPC服務需要超過幾毫秒的時間才能完成地話,
你應該避免在Activity/View線程中調用。
只有方法才獲得支持,換句話就是不支持變量。
你不能在AIDL接口中聲明靜態屬性。
現在你已完成了接口的實現,你需要向客戶端公開該實現。這就是我們所熟悉的"發佈服務"。發佈一個Service,然後繼承Service並實現getBinder()返回一個實
現的類的實例。下面是個Service的代碼片斷,該Service向客戶端公了MDSInterface   接口。
public class MDService extends Service {
public IBinder onBind(Intent intent) {
return mBinder;
}
        private final MDSInterface.Stub mBinder = 
                                             new MDSInterface.Stub() {
}
 }
    現在被調用者已經全部實現了,接下來就是如何實現調用者端的操作了。
    下面是調用的代碼:
public class MusicDroid extends Activity {
private MDSInterface mpInterface;
public void onCreate(Bundle icicle) {
//------------------------------------------bindService(new Intent(MusicDroid.this, 
MDService.class),
mConnection, Context.BIND_AUTO_CREATE);
        }
        private ServiceConnection mConnection = new 
ServiceConnection() 
            {
  public void onServiceConnected(ComponentName className, 
                IBinder service) {
mpInterface = MDSInterface.Stub.asInterface((IBinder) 
service);
}
public void onServiceDisconnected(ComponentName className) {
mpInterface = null;
}
};
}
從調用的代碼可以看出,要想調用Service時,必需還要有一個工具類ServiceConnection,這個可以有兩個必須要實現的函數,分別是:
public void onServiceConnected(ComponentName className, 
IBinder service) {}
此函數在系統啓動Service時調用,進行必要時初始化。
public void onServiceDisconnected(ComponentName className){}
此函數在系統斷開Service時調用,進行必要的析構操作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章