Intent Android 详解
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外數據類型也很重要.
例如, 一個顯示圖片的程序不應該用來處理聲音文件. 數據類型常??梢詮腢RI推斷, 特別是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)說明了組件通??梢詮奈募蚦ontent 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的標題, 并允許用戶編輯該標題.
?
轉載于:https://www.cnblogs.com/qiaoxu/p/4018349.html
總結
以上是生活随笔為你收集整理的Intent Android 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql相关操作(一)
- 下一篇: MAC使用技巧汇总