Android IntentFilter 匹配原則淺析 .

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的匹配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章