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

最后,該文章是經過我在互聯網中,某個文章中提取和加工而來,首先感謝原作者的精心設計,原文地址如下:http://blog.csdn.net/silenceburn/article/details/6083375


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM