Intent Android 詳解

來源:互聯網
上載者:User

標籤:android   http   color   io   os   使用   ar   for   檔案   

Intents and Intent Filters 三種應用程式基底本組件
activity, service和broadcast receiver——是使用稱為intent的訊息來啟用的。

 

Intent訊息傳遞是一種組件間運行時綁定的機制. intent是Intent對象, 它包含了需要做的操作的描述, 或者, 對於廣播來說, 包含了正在通知的訊息內容. 對於向這三種組件發送intent有不同的機制:
使用Context.startActivity() 或 Activity.startActivityForResult(), 傳入一個intent來啟動一個activity.
使用 Activity.setResult(), 傳入一個intent來從activity中返回結果.
將intent對象傳給Context.startService()來啟動一個service或者傳訊息給一個啟動並執行service.
將intent對象傳給 Context.bindService()來綁定一個service.
將intent對象傳給 Context.sendBroadcast(), Context.sendOrderedBroadcast(),或者Context.sendStickyBroadcast()等廣播方法,則它們被傳給 broadcast receiver.

在上述三種情況下,

android系統會自己找到合適的activity, service, 或者 broadcast receivers來響應intent. 三者的intent相互獨立互不干擾.

Intent Objects Intent對象 一個intent對象包含了接受該intent的組件的資訊(例如需要的動作和該動作需要的資料)和android系統所需要的資訊(例如該組件的類別,以及如何啟動它).

具體的說: 組件名稱 為一個ComponentName 對象. 它是目標組件的完整名(例如"com.example.project.app.FreneticActivity")和應用程式manifest檔案設定的包名(例如"com.example.project")的組合.

前者的包名部分和後者不一定一樣. 組件名稱是可選的. 如果設定了的話, Intent對象會被傳給指定的類的一個執行個體.

如果不設定, 則android使用其它資訊來定位合適的目標. 組件名稱是使用setComponent(), setClass(),或 setClassName()來設定, 使用 getComponent()來擷取.

Action 一個字串, 為請求的動作命名, 或者, 對於broadcast intent, 發生的並且正在被報告的動作.

例如: 常量 目標組件 動作

ACTION_CALL activity 發起一個撥打電話.

ACTION_EDIT activity 顯示資料給使用者來編輯.

ACTION_MAIN activity 將該activity作為一個task的第一個activity啟動,不傳入參數也不期望傳回值.

ACTION_SYNC activity 將裝置上的資料和一個伺服器同步.

ACTION_BATTERY_LOW broadcast receiver 發出電量不足的警告.

ACTION_HEADSET_PLUG broadcast receiver 一個耳機正被插入或者拔出.

ACTION_SCREEN_ON broadcast receiver 螢幕被點亮.

ACTION_TIMEZONE_CHANGED broadcast receiver 時區設定改變.

你也可以定義自己的action字串用來啟動你的應用程式. 自訂的action應該包含應用程式的包名.例如"com.example.project.SHOW_COLOR".

action很大程度上決定了intent的另外部分的結構, 就像一個方法名決定了它接受的參數和傳回值一樣.

因此, 最好給action一個最能反映其作用的名字. 一個intent對象中的action是使用getAction()和setAction()來讀寫的.

Data 需要操作的資料的URI和它的MIME(多用途互連網郵件擴充,Multipurpose Internet Mail Extensions)類型.

例如, 如果action為ACTION_EDIT, 那麼Data將包含待編輯的資料URI. 如果action為ACTION_CALL, Data將為tel:電話號碼的URI.

如果action為ACTION_VIEW, 則Data為http:網路地址的URI. 當將一個intent和一個組件相匹配時, 除了URI外資料類型也很重要.

例如, 一個顯示圖片的程式不應該用來處理音效檔. 資料類型常常可以從URI推斷, 特別是content:URI, 它表示該資料屬於一個content provider.

但資料類型也可以被intent對象顯示聲明. setData()方法設定URI, 而setType()方法指定MIME類型, setDataAndType()設定資料URI和MIME類型.

它們可以使用getData()和getType()來讀取. Category 一個字串,包含了關於處理該intent的組件的種類的資訊. 一個intent對象可以有任意個category.

intent類定義了許多category常數,

例如: 常量 含義 CATEGORY_BROWSABLE 目標activity可以使用瀏覽器來顯示-例片或電子郵件訊息.

CATEGORY_GADGET 該activity可以被包含在另外一個裝載小工具的activity中.

CATEGORY_HOME 該activity顯示主畫面,也就是使用者按下Home鍵看到的介面.

CATEGORY_LAUNCHER 該activity可以作為一個任務的第一個activity,並且列在應用程式啟動器中.

CATEGORY_PREFERENCE 該activity是一個選項面板.

addCategory()方法為一個intent對象增加一個category, removeCategory刪除一個category, getCategories()擷取intent所有的category. Extras 為鍵-值對形式的附加資訊.

例如ACTION_TIMEZONE_CHANGED的intent有一個"time-zone"附加資訊來指明新的時區, 而ACTION_HEADSET_PLUG有一個"state"附加資訊來指示耳機是被插入還是被拔出.

intent對象有一系列put...()和set...()方法來設定和擷取附加資訊. 這些方法和Bundle對象很像. 事實上附加資訊可以使用putExtras()和getExtras()作為Bundle來讀和寫. Flags 各種標誌.

很多標誌指示android系統如何啟動一個activity(例如該activity屬於哪個任務)和啟動後如何處理它(例如, 它是否屬於最近activity列表中). android系統和應用程式使用intent對象來送出系統廣播和啟用系統定義的組件.

Intent Resolution Intent解析

intent有兩種: 顯式intent使用名字來指定目標組件. 由於組件名稱一般不會被其它開發人員所熟知, 這種intent一般用於應用程式內部訊息-- 例如一個activity啟動一個附屬的service或者另一個activity. 隱式intent不指定目標的名稱. 一般用於啟動其它應用程式的組件. Android將顯式intent發送給指定的類. intent對象中名字唯一決定接受intent的對象.

對於隱式intent, android系統必須找到最合適的組件來處理它. 它比較intent的內容和intent filter. intent filter是組件的一個相關結構, 表示其接受intent的能力.

android系統根據intent filter開啟可以接受intent的組件. 如果一個組件沒有intent filter, 那麼它只能接受顯式intent. 如果有, 則能同時接受二者. 當一個intent和intent filter比較時,

只考慮三個屬性: action, data, category. extra和flag在intent解析中沒有用. Intent filters activity, service和broadcast receiver可以有多個intent filter來告知系統它們能接受什麼樣的隱式intent.

intent filter的名字很形象: 它過濾掉不想接受的intent, 留下想接受的intent.

顯式intent無視intent filter. 一個組件對能做的每件事有單獨的filter. 例如, 記事本程式的NoteEditor activity有兩個filter --

一個啟動並顯示一個特定的記錄給使用者查看或編輯, 另一個啟動一個空的記錄給使用者編輯. Filters and security Filter和安全 一個intent filter不一定安全可靠.

一個應用程式可以讓它的某個組件去接受隱式intent, 但是它沒法防止這個組件接受顯示intent. 其它的程式總是可以使用自訂的資料加上顯式的程式名稱來調用該組件.

一個intent filter是IntentFilter類的執行個體, 但是它一般不出現在代碼中,而是出現在android Manifest檔案中, 以的形式. (有一個例外是broadcast receiver的intent filter是使用 Context.registerReceiver()來動態設定的, 其intent filter也是在代碼中建立的.)

一個filter有action, data, category等欄位.

一個隱式intent為了能被某個intent filter接受, 必須通過3個測試.

一個intent為了被某個組件接受, 則必須通過它所有的intent filter中的一個. Action 測試 . . .

一個intent對象只能指定一個action, 而一個intent filter可以指定多個action. action列表不可為空, 否則它將組織所有的intent.

一個intent對象的action必須和intent filter中的某一個action匹配, 才能通過. 如果intent filter的action列表為空白, 則不通過. 如果intent對象不指定action, 並且intent filter的action列表不為空白, 則通過. Category 測試 . . .

注意前面說到的對於action和category的常數是在代碼中用的,而不是manifest檔案中用的. 例如, CATEGORY_BROWSABLE常數對應xml中的表示為"android.intent.category.BROWSABLE".

一個intent要通過category測試, 那麼該intent對象中的每個category都必須和filter中的某一個匹配. 理論上來說,

一個intent對象如果沒有指定category的話, 它應該能通過任意的category 測試.

有一個例外: android把所有的傳給startActivity()的隱式intent看做至少有一個category: "android.intent.category.DEFAULT".

因此, 想要接受隱式intent的activity必須在intent filter中加入"android.intent.category.DEFAULT". ("android.intent.action.MAIN" 和"android.intent.category.LAUNCHER"的intent filter例外.

它們不需要"android.intent.category.DEFAULT".) Data test . . .

每個元素指定了一個URI和一個資料類型. URI每個部分為不同的屬性 -- scheme, host, port, path: scheme://host:port/path

例如, 在如下的URI中: content://com.example.project:200/folder/subfolder/etc scheme為"content", host為"com.example.project", port為"200", path為"folder/subfolder/etc".

host和port一起組成了URI authority. 如果host未指定,則port被忽略. 這些屬性都是可選的,但它們並非相互獨立: 要使一個authority有意義,必須指定一個scheme.

要使一個path有意義, 必須指定一個scheme和一個authority. 當intent對象中的URI和intent filter中相比較時, 它只和filter中定義了的部分比較.

例如, 如果filter中之定義了scheme,那麼所有包含該scheme的URI的intent對象都通過測試.對於path來說,可以使用萬用字元來進行部分匹配. 元素的type屬性指定了資料類型.

它在filter中比在URI中更常見. intent對象和filter都可以使用"*"萬用字元作為子類型.

例如"text/*" "audio/*"表示所有的子類型都匹配.

data測試的規則如下: 一個不含uri也不含資料類型的intent對象只通過兩者都不包含的filter.

一個含uri但不含資料類型的intent對象(並且不能從uri推斷資料類型的)只能通過這樣的filter: uri匹配, 並且不指定類型. 這種情況限於類似mailto:和tel:這樣的不指定實際資料的uri.

一個只包含資料類型但不包含URI的intent只通過這樣的filter: 該filter只列出相同的資料類型, 並且不指定uri.

一個既包含uri又包含資料類型的intent對象只通過這樣的filter: intent對象的資料類型和filter中的一個類型匹配, intent對象的uri要麼和filter的uri匹配, 要麼intent對象的uri為content:或者file:, 並且filter不指定uri.

如果一個intent可以通過多於一個activity或者service的filter, 那麼使用者可能會被詢問需要啟動哪一個.

如果一個都沒有的話, 那麼會拋出異常. Common cases 常見情況 上述的最後一個規則(d)說明了組件通常可以從檔案和content provider中擷取資料.

因此, 它們的filter可以只列出資料類型不列scheme. 這是個特殊情況.

下列元素告訴android該組件可以從一個content provider取得映像資料並顯示之: 由於大部分可用的資料由content provider提供, 指定資料類型但不指定uri的filter是最常見的情況.

另外一個常見的配置是filter具有一個scheme和一個資料類型. 例如, 下列元素告訴android該component可以從網路擷取映像資料並顯示之: 考慮使用者點擊一個網頁時瀏覽器的動作.

它首先試圖顯示這個資料(當做一個html頁來處理). 如果無法顯示, 則建立一個隱式intent, 並啟動一個可以處理它的activity.

如果沒有這樣的activity, 那麼它請求下載管理員來下載該資料. 然後它將資料置於一個content provider的控制之下,

這樣有很多activity(擁有只有資料類型的filter)可以處理這些資料. 大部分應用程式還有一種方法來單獨啟動, 不需要引用任何特定的資料.

這些能啟動應用程式的activity具有action為"android.intent.action.MAIN" 的filter. 如果它們需要在應用程式啟動器中顯示,

它們必須指定"android.intent.category.LAUNCHER" 的category. Using intent matching 使用intent匹配 intent和intent filter相匹配,

不僅為了尋找並啟動一個目標組件, 也是為了尋找裝置上組件的資訊. 例如, android系統啟動了應用程式啟動器, 該程式位於螢幕的頂層, 顯示了使用者可以啟動的程式,

這是通過尋找裝置上所有的action為"android.intent.action.MAIN" ,category為"android.intent.category.LAUNCHER"的intent filter所在的activity實現的.

然後它顯示了這些activity的表徵圖和標題. 類似的, 它通過尋找 "android.intent.category.HOME"的filter來定位主畫面程式.

應用程式可以用相同的方式來使用intent匹配. PackageManager 有一組query...()方法來尋找接受某個特定intent的所有組件,

還有一系列resolve...()方法來決定響應一個intent的最佳組件. 例如, queryIntentActivities()返回一個activity列表,

這些activity可以執行傳入的intent. 類似的還有queryIntentServices()和queryIntentBroadcastReceivers(). Note Pad Example

例子:記事本 記事本樣本程式讓使用者可以瀏覽一個筆記列表, 查看, 編輯, 刪除和增加筆記. 這一節關注該程式定義的intent filter.

在其manifest檔案中, 記事本程式定義了三個activity, 每個有至少一個intent filter. 它還定義了一個content provider來管理筆記資料.

manifest 檔案如下: 第一個activity, NoteList, 和其它activity不同, 因為它操作一個筆記的目錄(筆記列表), 而不是一個單獨的筆記. 它一般作為該程式的初始介面.

它可以做以下三件事:

該filter聲明了記事本應用程式的主入口. 標準的MAIN action是一個不需要任何其它資訊(例如資料等)的程式入口, LAUNCHER category表示該入口應該在應用程式啟動器中列出.

該filter聲明了改activity可以對一個筆記目錄做的事情. 它允許使用者查看或編輯該目錄(使用VIEW和EDIT action), 或者選取特定的筆記(使用PICK action). 元素的mimeType指定了這些action可以操作的資料類型.

它表明該activity可以從一個持有記事本資料的content provider(vnd.google.note)取得一個或多個資料項目的Cursor(vnd.android.cursor.dir).

注意該filter提供了一個DEFAULT category. 這是因為 Context.startActivity() 和 Activity.startActivityForResult()方法將所有的intent都作為作為包含了DEFAULT category來處理,

只有兩個例外: 顯式指明目標activity名稱的intent. 包含MAIN action 和LAUNCHER category的intent.

因此, 除了MAIN和LAUNCHER的filter之外, DEFAULT category是必須的. 這個filter描述了該activity能夠在不需要知道目錄的情況下返回使用者選擇的一個筆記的能力.

GET_CONTENT action和PICK action相類似. 在這兩者中, activity都返回使用者選擇的筆記的URI. (返回給調用startActivityForResult()來啟動NoteList activity的activity.)

在這裡, 調用者指定了使用者選擇的資料類型而不是資料的目錄. 這個資料類型, vnd.android.cursor.item/vnd.google.note, 表示了該activity可以返回的資料類型 --

一個筆記的URI. 從返回的URI, 調用者可以從持有筆記資料的content provider(vnd.google.note)

得到一個項目(vnd.android.cursor.item)的Cursor. 也就是說, 對於PICK來說, 資料類型表示activity可以給使用者顯式的資料類型.對於GET_CONTENT filter,

它表示activity可以返回給調用者的資料類型. 下列intent可以被NoteList activity接受: action: android.intent.action.MAIN

不指定任何資料直接啟動activity. action: android.intent.action.MAIN category: android.intent.category.LAUNCHER

不指定任何資料直接啟動activity. 這是程式啟動器使用的intent.

所有使用該組合的filter的activity

被加到啟動器中. action: android.intent.action.VIEW data: content://com.google.provider.NotePad/notes

要求activity顯示一個筆記列表,這個列表位於content://com.google.provider.NotePad/notes.

使用者可以瀏覽這個列表並擷取清單項目的資訊. action: android.intent.action.PICK data: content://com.google.provider.NotePad/notes

請求activity顯示content://com.google.provider.NotePad/notes下的筆記列表.

使用者可以選取一個筆記, activity將返回筆記的URI給啟動NoteList的activity. action: android.intent.action.GET_CONTENT data type: vnd.android.cursor.item/vnd.google.note 請求activity提供記事本資料的一項.

第二個activity, NoteEditor, 為使用者顯示一個筆記並允許他們編輯它.

它可以做以下兩件事: 這個activity的主要目的是使使用者編輯一個筆記--VIEW或者EDIT一個筆記. (在category中,EDIT_NOTE是EDIT的同義字.)

intent包含匹配MIME類型vnd.android.cursor.item/vnd.google.note的URI--也就是某一個特定的筆記的URI.

它一般來說是NoteList activity中的PICK或者GET_CONTENT action返回的. 像以前一樣,該filter列出了DEFAULT category. 該activity的第二個目的是使使用者能夠建立一個新的筆記, 並插入到已存在的筆記目錄中.

該intent包含了匹配vnd.android.cursor.dir/vnd.google.note的URI, 也就是筆 有了這些能力,

NoteEditor

就可以接受以下intent: action: android.intent.action.VIEW data: content://com.google.provider.NotePad/notes/ID

要求activity顯示給定ID的筆記. action: android.intent.action.EDIT data: content://com.google.provider.NotePad/notes/ID

要求activity顯示指定ID的筆記,然後讓使用者來編輯它. 如果使用者儲存了更改,則activity更新該content provider的資料.

action: android.intent.action.INSERT data: content://com.google.provider.NotePad/notes

要求activity建立一個新的空筆記在content://com.google.provider.NotePad/notes, 並允許使用者編輯它,

如果使用者儲存了更改,則該URI被返回給調用者. 最後一個activity, TitleEditor, 允許使用者編輯筆記的標題.

這可以通過直接調用activity(在intent中設定組件名稱)的方式來實現. 但是這裡我們用這個機會來展示如何在已有資料上進行另外的操作(類似於windows中的開啟檔案->程式列表 -- 譯者注):

它必須在一個特定的筆記上調用(data type vnd.android.cursor.item/vnd.google.note), 就像之前的VIEW和EDIT action一樣. 然而, 這裡activity顯示筆記資料中包含的標題,

而不是內容. 除了支援DEFAULT category之外,title編輯器還支援了另外兩個category:

ALTERNATIVE 和SELECTED_ALTERNATIVE. 這些category標誌著activity可以在選項菜單中呈現給使用者(就像LAUNCHER category表示activity可以在程式啟動器中一樣).

注意filter還提供了一個顯示標籤(android:label="@string/resolve_title")來更好的控制使用者在選項菜單中看到的內容.

有了這些能力, 以下的intent就可以被TitleEditor接受: action: com.android.notepad.action.EDIT_TITLE data: content://com.google.provider.NotePad/notes/ID 要求activity顯示給定筆記ID的標題, 並允許使用者編輯該標題.

 

Intent Android 詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.