編輯:關於Android編程
如果對Intent不是特別了解,可以參見博文《Android中Intent概述及使用》,該文對本文要使用的action、category以及data都進行了詳細介紹。
本文內容有點長,希望大家可以耐心讀完。
本文在描述組件在manifest中注冊的Intent Filter過濾器時,統一用intent-filter表示。
我們知道,Intent是分兩種的:顯式Intent和隱式Intent。如果一個Intent明確指定了要啟動的組件的完整類名,那麼這個Intent就是顯式Intent,否則就是隱式Intent。當我們用一個顯式Intent去啟動組件時,Android會根據Intent對象所提供的component name直接找到要啟動的組件,當我們用一個隱式的Intent去啟動組件時,Android系統就無法直接知道要啟動的組件名稱了,本文就是講解Android系統如何根據隱式Intent查找匹配到要啟動的組件。
當Android系統接收到一個隱式Intent要啟動一個Activity(或其他組件)時,Android會根據以下三個信息比較Intent的信息與注冊的組件的intent-filter的信息,從而為該Intent選擇出最匹配的Activity(或其他組件):
intent中的action intent中的category intent中的data(包含Uri以及data的MIME類型)也就是隱式intent對象要滿足要啟動的目標組件中注冊的intent-filter中的、
、三個標簽中的信息,即要分別通過action測試、category測試以及data測試。intent-filter信息是在Android的manife文件中描述的,顧名思義,intent-filter是intent過濾器,就是用來過濾intent的。
如果隱式intent對象同時通過了某個組件的中intent-filter的action測試、category測試以及data測試,那麼該組件就可以被intent對象所啟動。如果隱式intent對象沒有通過系統中任何組件的intent-filter測試,那麼就沒有Android系統無法找到該intent對象要啟動的組件。下面我們依次看一下如何才能通過這三個測試。
為了指定能夠接收並處理的Intent的類型,組件可以在intent-filter中聲明其支持0個或多個action,例如:
intent對象可以通過setAction()方法設置唯一的一個action值。對於action測試,需要分兩種情況:
intent對象設置了action
如果intent對象通過調用setAction()方法設置了action的值,那麼只有當組件的intent-filter中包含了intent對象中的action值的時候,action測試才通過,否則無法通過。
舉個例子,假設我們的Activity的intent-filter如下所示:
下面的intent對象可以通過上面intent-filter裡面的action測試:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
Uri uri = Uri.parse(ispring://blog.csdn.net/sunqunsunqun);
intent.setData(uri);
該intent之所以能通過action測試是因為intent-filter中包含該intent的action值com.ispring.action.ACTION_TEST1。
下面的intent對象無法通過上面intent-filter裡面的action測試:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST3);
Uri uri = Uri.parse(ispring://blog.csdn.net/sunqunsunqun);
intent.setData(uri);
該intent之所以無法通過action測試是因為intent-filter中不包含該intent的action值com.ispring.action.ACTION_TEST3。
intent對象沒有設置action
如果intent對象沒有調用setAction()方法設置action的值,那麼如果intent-filter至少有一個任意的action的值,該intent對象就可以通過該intent-filter的action測試,反之,如果intent-filter中沒有定義任何的action,那麼該intent無法通過該intent-filter的action測試。
舉個例子,假設我們的intent對象如下所示:
Intent intent = new Intent();
//不設置action值
//intent.setAction(com.ispring.action.ACTION_TEST1);
Uri uri = Uri.parse(ispring://blog.csdn.net/sunqunsunqun);
intent.setData(uri);
上面的intent對象可以通過如下的intent-filter:
上面的intent對象無法通過如下的intent-filter:
通過上面的幾個示例,想必大家都已經理解了action測試的規則,至於上面的category和data標簽的使用,會在下面詳細介紹。
總結起來有兩點結論:
1. 要想讓intent對象通過action測試,那麼intent-filter中聲明的action不能為空且要包含intent對象中的action值(如果intent的action值不為空的話)。
2. 如果intent-filter沒有聲明任何action,那麼所有的intent的對象(即無論intent如何配置)都無法通過intent-filter的action測試。
為了指定能夠接收並處理的Intent的類型,組件可以在intent-filter中聲明其支持0個或多個category,例如:
...
intent對象有addCategory()方法,也就是說一個intent對象也可以關聯多個category。為了能讓intent對象通過intent-filter的category測試,intent對象中的所有category都要在intent-filter中找到對應項。
具體來說,又分為如下兩種情況:
intent對象至少有一個category
這種情況下,假設intent對象有N個category(N >=1),那麼intent-filter中必須至少要包含這N個category,intent對象才能通過category測試,否則無法通過測試。
舉個例子,假設我們的intent-filter如下所示:
以下intent對象能夠通過category測試
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
intent.addCategory(com.ispring.category.TEST1);
intent.addCategory(com.ispring.category.TEST2);
該intent對象之所以可以通過category測試是因為intent-filter包含了該intent對中所有的category值:com.ispring.category.TEST1”和com.ispring.category.TEST2。
以下intent對象無法通過category測試
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
intent.addCategory(com.ispring.category.TEST1);
intent.addCategory(com.ispring.category.TEST3);
該intent之所以無法通過上面的intent-filter的category測試是因為intent-filter只包含了該intent中值為com.ispring.category.TEST1的category,而並未包含值為com.ispring.category.TEST3的category,不滿足完全包含intent中全部category的情況。
intent對象不包含任何category
如果intent對象沒有調用過addCategory()方法,那麼intent對象就不包含任何的category。這種情況下,無論intent-filter中category中如何配置,intent對象總是能通過intent-filter的category測試,即便intent-filter中沒有聲明任何的category,intent都能通過category測試。
此處需要特別說明的是,我們在上面所有的示例中,都給Activity的intent-filter添加了值為android.intent.category.DEFAULT
的category,這是因為當我們把一個隱式的intent傳遞給startActivity()
或startActivityForResult()
方法時,Android會自動給該隱式intent添加值為android.intent.category.DEFAULT
的category,所以為了能讓intent-filter包含intent中全部的category,我們就需要在Activity的intent-filter中添加該category,在使用時需要特別注意。
根據上面我們的幾個示例,我們總結如下:
1. 不包含任何category的intent總是能通過所有任意的intent-filter的category測試;
2. 如果intent對象包含category(至少一個),那麼只有當intent-filter中聲明的category全部包含intent對象中的所有category的時候才通過category測試。
3. 如果允許Activity被隱式的Intent啟動,那麼我們必須在該Activity的intent-filter中聲明值為android.intent.category.DEFAULT
的category。
為了指定可以接收的Intent的data,intent-filter需要聲明0個多多個標簽,例如:
...
每個標簽都可以指定一個URI結構以及data的MIME類型。一個完整的URI由
scheme
、host
、port
和path
組成,其結構如下所示:
其中scheme既可以是Android中常見的協議,也可以是我們自定義的協議。Android中常見的協議包括content協議、http協議、file協議等,自定義協議可以使用自定義的字符串。
如下是一個content協議的URI:
content://com.example.project:200/folder/subfolder/etc
在該URI中,scheme是content,host是com.example.project,port是200,path是folder/subfolder/etc。
如下是一個自定義協議的URI:
ispring://blog.csdn.net/sunqunsunqun
在該URI中,scheme是ispring,host是blog.csdn.net,沒有明確設定port,path是sunqunsunqun。
組成URI的這些屬性在標簽中都是可選的 ,但存在如下的依賴關系:
當我們將intent對象中的Uri參數與intent-filter中的標簽指定的URI格式進行對別時,我們我們只對比intent-filter的
標簽指定的部分,例如:
需要注意的是,intent-filter的標簽在指定path的值時,可以在裡面使用通配符
*
,起到部分匹配的效果。
data測試需要同時將intent對象中的URI、MIME類型與intent-filter的標簽中指定的URI、MIME類型進行對比。
我們知道一個intent-filter下可以有多個標簽,intent對象無需通過所有的
標簽測試,一般情況下,我們的intent對象只需通過了其中一個
標簽的測試並滿足某些特定情形下的一些條件,那麼該intent對象就通過了該intent-filter的data測試。
進行對比的規則分以下幾種情況:
intent對象不包含URI和MIME類型
這種情況下,只有當intent-filter也沒有指定任何URI和MIME類型的時候才能通過data測試。
例如我們有如下intent對象:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
上面的intent對象可以通過下面的intent-filter的data測試:
上面的intent對象無法通過下面的intent-filter測試:
intent對象包含URI但不包含MIME類型
這種情況下,只有當intent對象的URI匹配到了intent-filter中的URI格式,並且intent-filter沒有指定MIME類型的時候才能通過data測試。需要注意的是,這裡所說的intent-filter沒有指定MIME類型的情形指的是intent-filter中所有的標簽都沒有指定MIME類型,即整個intent-filter中完全沒有
android:mimeType
這幾個字,理解這點很重要,大家在下面的幾個示例中可以體會到這點。
例如有如下intent對象:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
Uri uri = Uri.parse(ispring://blog.csdn.net/sunqunsunqun);
intent.setData(uri);
上面的intent能通過如下的intent-filter的data測試:
上面的intent對象可以通過以下intent-filter的data測試:
intent對象雖然不能通過scheme為sunqun的標簽測試,但是可以通過scheme為ispring的data標簽測試,且intent對象和intent-filter中的兩個
標簽都沒有指定MIME,所以上面的intent對象可以通過該intent-filter測試。
上面的intent對象無法通過以下intent-filter的標簽測試:
上面的intent對象之所以不能通過intent-filter中唯一的一個標簽測試是因為我們的intent對象沒有指定MIME類型,但是上面的
標簽通過
android:mimeType=text/plain
設置了MIME類型。
上面的intent對象無法通過以下intent-filter的data測試:
上面的intent對象之所以無法通過該intent-filter中的data測試,是因為intent對象沒有設置MIME類型,但是intent-filter中第二個data標簽通過android:mimeType=text/plain
設置了MIME類型。
intent對象包含MIME類型但不包含URI
這種情況下,只有當intent中的MIME類型與intent-filter中列出的MIME類型相同,並且intent-filter沒有指定任何的URI格式的時候才能通過data測試。需要注意的是,這裡所說的intent-filter沒有指定任何的URI格式的情形指的是intent-filter中所有標簽都沒有指定URI,即整個intent-filter中完全沒有
android:scheme
、android:host
、android:port
以及android:path
,理解這點很重要,大家在下面的幾個示例中可以體會到這點。
例如有如下intent對象:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
intent.setType(text/plain);
上面的intent對象可以通過以下intent-filter的data測試:
上面的intent對象可以通過下面的intent-filter的data測試:
上面的intent對象雖然沒有通過MIME類型為image/*
的第一個data標簽測試,但能通過第二個data標簽測試,並且intent對象和intent-filter都沒有指定任何的URI格式。
上面的intent對象不能通過以下intent-filter中的data測試:
上面的intent對象中沒有設置URI信息,但是在該intent-filter中設置了URI中的scheme值,所以intent無法通過intent-filter的data測試。
上面的intent對象無法通過以下intent-filter中的data測試:
上面的intent對象沒有指定URI信息,但是上面的intent-filter中第二個標簽設置了URI中的scheme信息,所以intent對象無法通過該intent-filter的data測試。
intent對象同時包含URI和MIME類型
這種情況下,要分別測試URI以及MIME類型測試是否通過,只有URI以及MIME測試都通過了,data測試才能通過。
標簽中的MIME類型值,那麼MIME類型測試就通過了。 對於URI測試:
中的URI,那麼URI測試就通過了。 如果intent的URI是content:
協議或file:
協議,並且整個intent-filter的所有
標簽中都沒有指定URI,那麼該intent也能通過URI測試。換句話說,如果一個intent-filter只列出了MIME類型,沒有列出任何URI相關的格式的話,那麼這個intent-filter就默認是支持content:
協議或file:
協議的。
下面舉幾個例子大家自己體會一下。
假設有如下協議為自定義協議ispring:
的intent對象:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
Uri uri = Uri.parse(ispring://blog.csdn.net/sunqunsunqun);
String type = text/plain;
intent.setDataAndType(uri, type);
上面的intent對象可以通過下面的intent-filter的data測試:
上面的intent對象無法通過下面的intent-filter的data測試:
port不滿足,URI測試不通過,導致data測試失敗。
上面的intent對象無法通過下面的intent-filter的data測試:
android:mimeType
不滿足,MIME類型測試不通過,導致data測試失敗。
假設有如下協議為content:
的intent對象:
Intent intent = new Intent();
intent.setAction(com.ispring.action.ACTION_TEST1);
Uri uri = Uri.parse(content://com.ispring.test);
String type = text/plain;
intent.setDataAndType(uri, type);
上面的intent對象無法通過下面的intent-filter的data測試:
URI中的scheme不匹配,導致URI測試不通過,導致data測試失敗。
上面的intent對象可以通過下面的intent-filter的data測試:
intent中使用的是content:
協議,並且整個intent-filter中都沒有定義URI格式,所以URI測試是可以通過的,並且MIME類型能找到匹配項,所以可以通過data測試。
綜上,我們就完成了對Intent中action、category、data測試的詳細解釋,本文所有示例代碼均在Android Studio 1.0正式版中驗證過沒有問題。很感謝大家能夠耐心讀完本博文,希望本文對大家正確使用Intent過濾器有所幫助。
許多項目都必須用到上傳圖片的功能,有了圖片會更加精彩,最近我的項目也需要選擇圖片的功能,所以把我寫的代碼共享出來,也算是筆記吧!好,廢話少說,下面看看效果圖: 效果還
本文為大家分享Android登陸界面實現清除輸入框內容和震動效果的全部代碼,具體內容如下:效果圖:主要代碼如下自定義的一個EditText,用於實現有文字的時候顯示可以清
代碼不多,就懶得加注釋了.原諒我的懶. 縮略圖獲取那塊,沒有加用線程.可能會在有些低端機上面或者高清的視頻會出現FC的情況.需要的童鞋.自行添加. &nb
說到ListView和GridView大家肯定不陌生,相信也有很多人已經使用到了出神入化的地步,因為這兩個控件實在是太常用了,可以說任何項目都會有ListView的身影,