[轉載請註明出處] http://kezeodsnx.pixnet.net/blog

作者: kezeodsnx

本篇主要參考intent and intent filter,加上個人說明與補充而成。

引言

對一個android的應用程式而言,最重要的檔案是AndroidManifest.xml。它負責向下一層的framwork註冊該應用程式,包括此應用程式的名字,位置 (哪個category),用哪個icon,有什麼功能 (avtivity,service,broadcast receiver,content provider)等等。使得framework (package manager)接到通知 (intent)時,能夠根據目前系統註冊的情況,濾出符合條件的功能。

 

應用程式四大總成

android的應用程式可包含以下四種功能,每種功能也都需要在AndroidManifest.xml做宣告,在安裝應用程式時,讓package manager知道其包含哪些功能。以下用component來代表這四種功能的集合。

1. Activity: 一般所指的activity是使用者看的到的介面,也就是UI,在android裡稱為View。一支應用程式可能有一個或以上的activity存在,每個activity也都會有自己的view。比如說一個看盤軟體,可能包含一個activity用來看大盤走勢,另一個activity來看自己的明牌,然後再一個acticity提供下單功能。系統會維護一個acticity的stack,用來記錄activity間的切換。

2. Service: 相較於activity,service並沒有UI,而比較像daemon,是一支run在background的程式。比如說download一個file,就可以實作成一個download service,這樣在切換到另一component時,還可繼續download。其他的例子像music player,camera等都會有service,在切換之間,不會停止原本的操作。

3. brooadcast intent receiver: 這是用來讓應用程式接收事件 (event),有點像signal和handler。意即會有另外的activity/service等會發出event (intent),若該應用程式有註冊receiver,則可根據此event做相對應的處理。整個流程是由notification manager當中間人,接受event,並啟動對應的程式。

4. content provider: 這個東西就是database,也就是用來存取資料,不管是從檔案或是SQLite,主要是提供data-sharing。

 

Intent

先來幾個intent例子,讀起來會比較有感覺。

1. Uri uri = Uri.parse("http://google.com");

    Intent it = new Intent(Intent.ACTION_VIEW, uri)

2.Uri uri = Uri.parse("tel:0800956956");

   Intent it = new Intent(Intent.ACTION_DIAL, uri);

3. Uri uri = Uri.parse("mailto:latrell@gmail.com")

    Intent it = new Intent(Intent.ACTION_SENDTO, uri); 

紅色部分是ACTION,雙引號內的部分是data。

intent很像是一個事件 (event),是一個用來切換activity的物件。通常用來描述想要做什麼事,以白話來說,可以是"顯示chris的聯絡資料",或是"建立一個新的空白筆記本"。這樣的command會描述成一個intent的物件,然後傳到package manager,package manager查詢 (實作上為queryIntentActivities(),queryIntentServices()或queryBroadcastReceivers())之前註冊過的應用程式 (透過AndroidManifest.xml),來濾出哪些component符合這個intent的需求,然後執行。intent的資料結構組成如下:

1. action: 如前例,指定要做什麼動作,如diplay,insert,edit,call等。常見的action有MAIN, EDIT, VIEW, PICK,當然也可以自訂。broadcast的intent報告發生了什麼樣的事件,如ACTION_BATTERY_LOW,ACTION_HEADSET_PLUG,ACTION_SCREEN_ON和ACTION_TIMEZONE_CHANGED。在填寫intent時,可透過setAction設定或getAction讀取。

2. data: 即URI,使用MIME的type宣告,通常會與哪種action產生關聯。比如說,一個EDIT action,其data會伴隨著文件的URI; 而若action是CALL,則其data應為"tel:"這種URI。MIME的宣告也很重要,可避免發生如顯示圖檔的activity卻用了音效的component。一些action和data的例子如下:

ACTION_VIEW http://www.google.com.tw
ACTION_EDIT content://contacts/1
ACTION_VIEW geo:38.899533,-77.036476
ACTION_SENDTO mailto://whoever@always.suffer
ACTION_DIAL tel:0800000123
ACTION_DELETE "package", strPackageName, null

3. Category: 指定更多的資訊來確認哪個component要來處理該intent,一個intent可以指定任意數量的category。預設的category有:

CATEGORY_BROWSABLE

CATEGORY_GADGET

CATEGORY_HOME

CATEGORY_LAUNCHER

CATEGORY_PREFERENCE

4. component: 指定哪個component應該處理該intent。這個情況比較特別,若指定了component,其他的項目將不再做match。因此需指定fully qualified的package name,如com.example.project.app.FreneticActivity。可用 setComponent(), setClass(),  setClassName()設定,getComponent()讀取。

5. Extra: 用來在intent中附加資訊,可用來傳遞資訊。比如說一個 ACTION_TIMEZONE_CHANGED需告訴處理的component要換到哪一個zone,就可在extra裡"bundle"這個新的zone。

6. FLAGS: 指定屬性,如用什麼方式啟動一個activity,或是launch之後要做什麼處置,如FLAG_ACTIVITY_CLEAR_WHRN_TASK_RESET,FLAG_ACTIVITY_EXCLUDE_WHEN_TASK_RESET,FLAG_FROM_BACKGROUND

以上內容可參照intent class

小結
intent基本上是定義溝通的語言,讓系統和應用程式可以溝通,比如說"打電話給Chris"這樣的command如何讓系統做相對應的處理,中間的流程是如何串起來。當一個應用程式安裝到系統時,這個語言就多了一些,系統可處理更多的command。

 

Intent resolution

解析(resolution)意思就是分發,當一個intent產生,如何match到正確的component,這個流程就是resolution。

intent有二種:

Explicit intent: 明確的指定哪個compoent要來處理。然而,通常應用程式間並不知道別人的功能有什麼,所以如果是Explicit,大多用在同一個應用程式內。

Implicit intent: 也就是不指定,技術上來說,就是不填上面的component那欄啦。因為透過resolution,因此通常是用在啟動外部的component。

在過濾intent的流程裡,將測試三項東西:action,data (both URI and data type)和category,見下述。


Intent Filter

要讓系統知道implicit如何處理,每個component會有一到多個intent filter,用來描述該component能處理什麼樣的intent。因此,一個implicit intent必須要通過所有的"測試"(見下述),才會有compoent(s)處理。每個component可能有好些filter,因此fail的話會轉到下一個測試項目。每個測試也可以不止一項,比如說一個filter裡有3個action,2個category與1個data。以下介紹所謂的"測試":

1. extra與flag與測試無關。

2. Action test

example (in AndroidManifest.xml):

    <action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />

    每個filter至少要有一個action test,否則將無法轉到下一個測試。intent裡所指定的action必須match filter裡的其中一個。那intent或intent filter沒有指定action會發生什麼事呢?

    。filter: 所有intent都fail,自然也就無法match。

    。intent: 所有acton test都pass,前提是action test不為空。


3. Category test

example (in AndroidManifest.xml):

    <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

    可以不設定或一個以上。與action test不同的是,在intent所指定的每個category,都必須列在filter的category。定義上,intent若無指定category,則category就pass。但有例外:

    。implicit intent預設是屬於CATEGORY_DEFAULT。因此,若component需要接收implicit intent,就必須在intent filter裡加上"android.intent.category.DEFAULT"。

    。例外中的例外: 如果filter設定"android.intent.action.MAIN"和"android.intent.category.LAUNCHER",則不需指定DEFAULT也可接收implicit intent。

 

4. Data test

example (in AndroidManifest.xml):

    <data android:type="video/mpeg" android:scheme="http" . . . /> 
<data android:type="audio/mpeg" android:scheme="http" . . . />
可以不設定或一個以上。data用來指定URI和type(MIME media type)。URI可分為4個部分: scheme, host, port, and path。格式為scheme://host:port/path。host跟port合稱authority
,例如:
content://com.example.project:200/folder/subfolder/etc

  每個部份都是optional,但有相依性。要設定authority,就必須指定scheme; 要設定path,authority跟path都要指定。

  比對intent裡的URI時有些原則: 只比對filter有設定的部份。比如說,filter只設定了scheme,那只要intent的scheme match,就pass。

  type用的是MIME格式,在filter裡指定type較URI常用。也支援萬用字元"*", 如 "text/*"表示text下所有的subtype都match。data test的比對規則如下:

  1. 若intent沒指定URI/data type且filter也沒指定,則pass

  2. 若intent只指定URI且此URI match filter裡的URL設定,則pass。但這只對mailto和tel這兩種scheme,其他像http這種可猜出 (infer)的scheme則不需指定 (因為可infer嘛)。

  3. 若intent指定data type,不指定URI且filter裡設定相同data type,也沒設定URI,則pass。

  4.若intent同時指定了type和URL,則分別討論: type若match filter裡指定的,那type的部分pass。URI若match filter裡指定的當然pass,但還有另一種情況也算pass: URI是content或file且filter沒有指定URI。換句話說,如果filter沒有指定type,設計上如果沒有指定URI,是一定會支援 (pass)content和file這兩種URI。

    針對規則4還有一些補充說明。從local data或content provider取得資料是每個component的基本配備。因此,存取這些資料,通常filter只需設定data type,而不需設定content/file,如<data android:type="image/*" />就是從content provider抓image。而大部分都資料都是從content provider,因此這是很常見的用法

小結

若intent pass多個component,可能會由使用者來做出選擇; 若全部fail,則產生exception。

 

Intent matching on Launcher

intent matching這件事不只是在找符合的component,也可以用來搜尋device有哪些component,launcher就是一個例子。launcher是最上層的screen,用來顯示使用者可以執行哪些程式。對launcher而言,只要去尋找在filter裡有設定"android.intent.action.MAIN" action 和 "android.intent.category.LAUNCHER" categor即可完成lacuncher的任務。相同的,home screen也是一樣,把所有設定"android.intent.category.HOME"找出來放在home。

Reference

intent and intent filter

 

kezeodsnx 發表在 痞客邦 PIXNET 留言(2) 人氣()


留言列表 (2)

發表留言
  • Michelle
  • 您好,您有提到Action可以自訂,
    請問要如何自訂呢?
    謝謝.
  • Quentin Tsai
  • Very useful and clear explanation!!! Thank you!!