關於Intent的使用,其實已經有很多文章進行了詳細的介紹,包括谷歌開發者網站也有進行很詳細的介紹。這裏再重複這個輪子的過程,主要是加深自己對Intent的認識,以及方便之後的查閱。
1、Intent是什麼
Intent是一個消息傳遞對象,可以使用它來完成對其它應用組件的請求操作。從這裏可以看出,Intent是一個對象,它的主要功能有兩個一個是傳遞消息,另外一個就是請求應用組件了,而這個傳遞消息也就是向請求的應用組件來傳遞的消息。
Inent請求的應用組件主要有三類
*請求Activity
通過將 Intent 傳遞給 startActivity(),可以啓動新的 Activity 實例。Intent 描述了要啓動的 Activity,並攜帶了任何必要的數據。
*請求Service
通過將 Intent 傳遞給 startService(),可以啓動服務執行一次性操作(例如,下載文件)。Intent 描述了要啓動的服務,並攜帶了任何必要的數據。
*請求Broadcast
通過將 Intent 傳遞給 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),可以將廣播傳遞給本應用或者其他應用。
2、Intent的分類
Intent在實際使用過程總可以根據其請求組件的方式來分成隱式Intent以及顯示Intent
2.1、顯示Intent
當在使用Intent請求組件時,按名稱(完全限定類名)指定要啓動的組件,我們吧這種Intent叫做顯示Intent,顯示Intent的使用範圍很廣,平時在Activity頁面跳轉時就基本都是使用的顯示Intent,如下所示
Intent intent = new Intent(this,TestActivity.class);
startActivity(intent);
這種使用方式使用的Intent,就是顯示Intent,顯示Intent傳遞數據常常通過intent.putExtra()的方式來進行
intent.putExtra("key","value");
2.2、隱式Intent
當在使用Intent請求組件時,與隱式Intent相反,顯示Intent不會指定特定的組件,而是聲明要執行的常規操作(action),從而允許其他應用中的組件來處理它,說的比較玄乎,直接看看代碼就能明白。
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
這裏的Intent.ACTION_DIAL對應字符串
public static final String ACTION_DIAL = "android.intent.action.DIAL";
而這裏就可以看出隱式Intent和顯示Intent的明顯不同了,但是有童鞋可能會疑惑了,根據這個Intent.ACTION_DIAL,怎麼調用起了系統的撥號界面了呢,這個就要細說隱式Intent了,這個放在下一節詳細介紹。
3、細說隱式Intent的使用
隱式Intent爲何根據字符串可以調用起來一個頁面呢,聰明的童鞋肯定能夠想那是因爲頁面和字符串存在一個對應關係,這就關係就是在被調動頁面的AndroidManifest.xml文件中進行定義了。
例如,這裏應用2中AndroidManifest.xml配置文件中對TargetActivity頁面進行如下配置
<activity android:name=".TargetActivity">
<intent-filter>
<action android:name="com.yoryky.intent.action.TARGET"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
之類看到對activity註冊添加了一個intent-filter 的標籤,這個標籤就是關鍵了,看名字也能大概知道這個標籤是用來過濾Intent啓動的組件的(這裏是Activity),這裏TargetActivity和action對應的name就形成了一個對應關係(並不一定是一一對應關係),我們便能夠其他應用中通過
Intent intent = new Intent("com.yoryky.intent.action.TARGET");
start(intent);
這種方式來啓動TargetActivity,當還有其它模塊的Activity也通過com.yoryky.intent.action.TARGET這個字符串來進行過濾的話,那麼以上intent請求的Activity組件便有多個,系統就會彈出提示框來讓用戶指定啓動的具體使哪一個Activity組件。
到這裏可能有同學會問了,以上intent-filter 標籤中除了action過濾外,不是還有個category麼
這個category標籤是用來聲明對應組件的類別的,Intent 過濾器既可以不聲明任何 category 元素,也可以聲明多個此類元素,當聲明瞭一個或者多個category 元素時,用來啓動該組件的Intent必須滿足category的過濾條件,才能啓動對應的組件。
實際上intent-filter 中除了可以添加action 以及category 這兩個標籤外,還可以添加data 標籤進行過濾。
在目標data標籤中包含了以下幾種子元素,它們定義了Uri的匹配規則:
android:scheme 匹配Uri中的前綴,除了“http”、“https”、“tel”…之外,我們可以定義自己的前綴
android:host 匹配Uri中的主機名部分,如“google.com”,如果定義爲“*”則表示任意主機名
android:port 匹配Uri中的端口
android:path 匹配Uri中的路徑
android:mimeType 匹配Uri路徑所指數據的MIME類型
例如這裏再AndroidManifest.xml中對TargetActivity作如下配置
<activity android:name=".TargetActivity">
<intent-filter>
<action android:name="com.yoryky.intent.action.TARGET" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="com.yoryky.example.data"
android:path="/target"
android:port="1122"
android:scheme="test"
android:minmeType="text/xml"/>
</intent-filter>
</activity>
這裏看到加入了data 標籤進行過濾,那麼在其它模塊中通過隱式Intent來請求這個TargetAcivity時,就必須嚴格按照data 標籤的過濾條件來啓動TargetActivity
Intent intent = new Intent("com.yoryky.intent.action.TARGET");
intent.setDataAndType(Uri.parse("test://com.yoryky.example.data:1122/target"),"text/xml");
startActivity(intent);
當然data 標籤不是必須的,data 標籤所包含的素數也不需要每種都使用來過濾,這樣過濾的條件也就會寬鬆一些。
需要注意的是,也是從 7.0 開始,Android SDK 中的 StrictMode 策略禁止開發人員在應用外部公開 file:// URI。具體表現爲,當我們在應用中使用包含 file:// URI 的 Intent 離開自己的應用時,程序會發生故障。
開發中,如果我們在使用 file:// URI 時忽視了這兩條規定,將導致用戶在 7.0 及更高版本系統的設備中使用到相關功能時,出現 FileUriExposedException 異常,導致應用出現崩潰閃退問題,而這兩個過程的替代解決方案便是使用 FileProvider,關於這方面的知識可以參考關於 Android 7.0 適配中 FileProvider 部分的總結 這篇文章。
到這裏我想總結的Intent知識就差不多了,有什麼問題還望各位童鞋多多指教。
參考文獻
2、關於 Android 7.0 適配中 FileProvider 部分的總結
5、Intent
6、URI