1 Intent分爲兩大類,顯式和隱式。
顯式事件,就是指通過 component Name 屬性,明確指定了目標組件的事件。
比如我們新建一個Intent,指名道姓的說,此事件用於啓動名爲"com.silenceburn.XXXX”
的Activity,那麼這就是一個顯式事件。
隱式事件,就是指沒有 component Name 屬性,沒有明確指定目標組件的事件。
比如系統向所有監控通話情況的程序發送的“來電話了!”的事件,由於系統不確定誰會處
理這個事件,因此係統不會明確指定目標組件,也就是說沒有目標組件,那麼這就是個隱式
的事件。
此處只是簡介顯式和隱式事件,更精確詳細的描述請查閱SDK文檔,我們只需要記住一點,
兩種事件的最大區別是 component Name 屬性是否爲空。
2 事件過濾策略 和 IntentFilter
系統在傳送顯式事件時非常方便,因爲如果把Intent比作一封信,那麼component Name就是
一個詳細的收件人地址,系統可以精確的把顯式事件送達目標組件。
而傳送隱式事件時,就比較麻煩了。因爲這封信的信封上,沒有寫收信地址!
那怎麼辦呢?系統做了一個艱難的決定,就是把信拆開看看。通過信件內容裏面的線索,去
尋找合適的收件人。
比如信中的線索描述到:“收信人是男性,快30歲了,未婚,喜歡玩遊戲”,那麼系統就在
小區裏面去找這樣的人。
非常值得慶幸的事情是,這個小區的人素質非常高,每戶人家都寫了點自我介紹在門口,
比如張三寫道:“我是男性,90後,未婚,喜歡玩遊戲”,李四寫道:“我是女性,快30歲
了,未婚,喜歡逛街”等等等等。
有了每戶人家的自我介紹,系統就能很快的定位真正的收件人了!
上面是一個類比的例子,不過android系統處理隱式事件的策略,基本上就是上述這種模式
了。
首先系統會通過觀察Intent的內容(打開信件看內容),取得匹配線索,系統所需的線索是
如下三種 :
action
data (both URI and data type)
category
其次,系統中每個組件,如果想收取隱式事件,則必須聲明自己的IntentFilter(自我介紹
,我對什麼樣的信件感興趣)。
至於怎麼寫IntentFilter,已經相當明瞭了,那就是應該是這樣寫:
"我是組件XXXX,我想要接收這樣的隱式事件:它的ACTION必須是 XXX,它的 category 必
須是 YYYY ,它包含的data必須是ZZZZ "
如果組件不聲明IntentFilter,那麼所有的隱式事件都不會發送給該組件。(注意,這並不
影響向該組件發送顯式事件。)
對於系統中發生的每個隱式事件,系統都會嘗試將 action, data , category 和系統中各
個組件聲明的 IntentFilter 去進行匹配,以找到合適的接收者。
3.IntentFilter匹配原則
對於顯式事件,系統可以精確送達。對於隱式事件,系統分析事件的 action, data ,
category 內容,並和各個組件聲明的IntentFilter進行匹配,找出匹配的組件進行送達。
action和category沒什麼好說的,再此我將最複雜的data匹配展開來進行描述一下:
首先務必認識到,data是一個相對複雜的要素。
data由URI來描述和定位,URI由三部分組成,
scheme://host:port/path 模式://主機:端口/路徑
此外在事件中,還可以設置data的MIME類型,作爲事件的datatype屬性。爲了描述方便,下
文將IntentFilter簡寫爲filter,請大家注意。
首先明確一個匹配原則,就是對於URI的匹配,只比較filter中聲明的部分。
部分匹配原則:只要filter中聲明的部分匹配成功,就認爲整個URI匹配成功。
舉例來說, content://com.silenceburn.SdCardTester:1000/mydata/private/
和filter定義爲 content://com.silenceburn.SdCardTester:1000/ 是可以匹配的。
注意filter中並沒有定義path部分,但是依然可以匹配成功,因爲filter不聲明的部分不進
行比較。
換句話講,任何符合content://com.silenceburn.SdCardTester:1000/的事件,無論path是
什麼,都可以匹配成功。
接下來是真正的data部分的,也就是URI的匹配規則如下:
1. 如果data的URI和datatype爲空,則 filter 的URI和type也必須爲空,才能匹配成功
2. 如果data的URI不爲空,但是datatype爲空,則 filter 必須定義URI並匹配成功,且
type爲空,才能匹配成功
3. 如果data的URI爲空,但是datatype不爲空,則 filter 必須URI爲空,定義type並匹配
成功,才能匹配成功
4. 如果data的URI和data都不爲空,則 filter 的URI和type都必須定義並匹配成功,才能
匹配成功。對於URI部分,有一個特殊處理,就是即使filter沒有定義URI,content和file
兩種URI也作爲既存的URI存在。
通過上文的描述,大家就可以明白爲什麼在註冊SD卡插拔接收器時,不但需要
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
而且需要添加
intentFilter.addDataScheme("file");
註冊應用安裝卸載事件時不但需要
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
而且需要
intentFilter.addDataScheme("package");
原因就在Data的匹配。