[轉載請註明出處] 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,見下述。
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不為空。
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
, andpath。格式為
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
留言列表