定義:Intent是一個訊息傳送物件,可以用它來訪問另外一個元件
可以用於以下三個場景:
- startActivity
startActivity()複製程式碼
startActivityForResult()複製程式碼
- startService
Android 5.0以上可以使用JobScheduler啟動
所有版本可以使用:startService(); bindService();複製程式碼
- sendBroadcast
三種呼叫方法sendBroadCast()複製程式碼
sendOrderedBroadCast()複製程式碼
sendStickyBroadcast()複製程式碼
Intent 型別
- 顯示型別
直接指定呼叫元件的名字,一般用於自己的APP內部 - 隱式型別
沒有指定元件的名字,而是宣告一般的action行為,用此方法可以允許呼叫另外一個APP的元件
啟動Service最好使用顯示Intent,否則會存在安全風險,因為無法確定service什麼時候被呼叫,而service又是使用者感知不到的元件
Android 5.0開始,如果bindService()隱式呼叫啟動service,會丟擲異常
Intent的建立
一個Intent物件包含了Android系統應該啟動哪個元件的資訊
一個Intent可以包含以下資訊:
componentName
指定需要啟動元件的名字
此項是可選的,用來區分顯示Intent和隱式Intent。
賦值的方法有以下幾種- Intent的構造方法
- setComponent()
- setClass()
- setClassName
action
指定Intent要完成的動作,為字串常量
action可自定義,也可使用系統的,一般自定義的話最好加上自己APP的包名字首
一些系統標準的Action常量
ACTION_VIEW,startActivity(),喚起系統相簿
ACTION_SEND,startActivity(),把一些資料傳送給另外的一些APP,如email,社交軟體等
ACTION_CALL,startActivity(),喚起打電話介面
不定期補充...
除了Intent定義了Action常量,其他的類也有定義,比如Settings,可以用來跳轉到系統指定的設定介面
action賦值的方法有一下幾種:- Intent的構造方法
- setAction()
data
根據給定的Uri尋找匹配的目標元件,如果不給定MIME型別,會進行推導,給定MIME型別,則強制使用此型別。
不同的Action有對應的data資料指定。
其中data的值設定為setData(),MIME的設定為setType()
常用值如下所示:
tel://: 號碼資料格式,後跟電話號碼。
mailto://: 郵件資料格式,後跟郵件收件人地址。
smsto://: 短息資料格式,後跟簡訊接收號碼。
content://: 內容資料格式,後跟需要讀取的內容。
file://: 檔案資料格式,後跟檔案路徑。
geo:// latitude, longitude:經緯資料格式,在地圖上顯示經緯度所指定的位置。
Uri指定資料指向那種資料格式,MIME指定資料具體的型別。比如Image和Audio有同樣的Uri,但是MIME的型別是不同的。setData()和setType()會互相覆蓋,所以當需要同時設定Uri和MIME時,為了避免這種情況,可以呼叫setDataAndType()
- category
執行Action的附加資訊。可以放置很多category,但是大多數intent是不需要category的
常用值如下:
CATEGORY_DEFAULT:Android系統中預設的執行方式,按照普通Activity的執行方式執行。
CATEGORY_HOME:設定該元件為Home Activity。
CATEGORY_PREFERENCE:設定該元件為Preference。
CATEGORY_LAUNCHER:設定該元件為在當前應用程式啟動器中優先順序最高的Activity,通常為入口ACTION_MAIN配合使用。
CATEGORY_BROWSABLE:設定該元件可以使用瀏覽器啟動。
CATEGORY_GADGET:設定該元件可以內嵌到另外的Activity中。
通過addCategory()指定 - extras
用來存放需要傳遞的資料,以鍵值對的形式進行儲存和訪問
通過putExtras()方法設定 - flags
設定Activity的啟動模式,例如:
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_NO_HISTORY
FLAG_ACTIVITY_SINGLE_TOP
具體的筆記放到Activity上
通過setFlags()方法設定
顯示Intent的例子
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);複製程式碼
隱式Intent的例子
其中resolveActivity()用來判斷Intent是否能夠被解析,防止APP崩潰
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
//Intent chooser = Intent.createChooser(sendIntent, title);//強制使用選擇器
//if (sendIntent.resolveActivity(getPackageManager()) != null) {
// startActivity(chooser);
//}
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}複製程式碼
接收一個隱式Intent
需要在manifest檔案中配置<intent-filter>,<intent-filter>包含如下三個子項:
<action>
<data>
<category>
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>複製程式碼
MIME型別 application/vnd.google.panorama360+jpg為指定的全景照片資料型別
<activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>複製程式碼
使用PendingIntent
PendingIntent是對Intent的包裝,使外部的APP能夠像在內部APP那樣對所包含的Intent進行使用
主要有如下的使用場景:
- Notification
- App Widget
- AlarmManager
取得例項的方法如下:
PendingIntent.getActivity(),啟動Activity
PendingIntent.getService(),啟動Service
PendingIntent.getBroadcast(),啟動BroadcastReceiver
狀態列通知:
int icon = android.R.drawable.my_icon;
long when = System.currentTimeMillis();//通知發生的時間為系統當前時間
Notification notification = new Notification(icon, null, when);//新建一個通知,第一個引數為圖示,第二個引數為短暫提示標題,第三個為通知時間
notification.defaults = Notification.DEFAULT_SOUND;//發出預設聲音
notification.flags |= Notification.FLAG_AUTO_CANCEL;//點選通知後自動清除通知
Intent openintent = new Intent(this, OtherActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);//當點選訊息時就會向系統傳送openintent意圖
notification.setLatestEventInfo(this, "標題", "內容", contentIntent);//setLatestEventInfo表示設定點選該通知的事件
int notifyCode = 0;
//獲取通知管理器
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notifyCode , notification);//第一個引數為自定義的通知唯一標識複製程式碼
action匹配規則
如果intent-filter設定了action的過濾規則,比如下面的XML程式碼,
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>複製程式碼
那麼:
- intent不設定action,則直接不通過
- intent設定了多個Action,則只要有一個匹配上,則可以通過
//不通過 Intent intent = new Intent();複製程式碼
//通過 intent.setAction("android.intent.action.EDIT");複製程式碼
//通過 intent.setAction("android.intent.action.EDIT"); intent.setAction("android.intent.action.test");複製程式碼
Category匹配規則
如果intent-filter設定了category的過濾規則,如下面的XML程式碼,
那麼:<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>複製程式碼
- Intent不設定category,則都通過,不論intent-filter設定多少category
- intent設定了category,intent上的category能夠匹配上intent-filter設定的category,才能夠通過
比如:
//通過
Intent intent = new Intent();複製程式碼
//通過
intent.addCategory("android.intent.category.DEFAULT"),可以匹配上複製程式碼
//通過
intent.addCategory("android.intent.category.BROWSABLE")複製程式碼
//不通過
intent.addCategory("android.intent.category.DEFAULT")
intent.addCategory("android.intent.category.test")複製程式碼
Data匹配規則
intent-filter中的結構由Uri和MIME Type組成
Uri包括如下幾部分:
scheme:整個Uri的模式,如http,ftp,content等
如果scheme未指定,則忽略host
如果只指定scheme,則所有和intent-filter相同的scheme都匹配host:Uri的域名,如www.google.com
如果host未指定,則忽略portport:Uri的埠
path:包含的路徑資訊,如:folder/subfolder/etc
如果scheme,host都未指定,則忽略path
整體組成:://:/
MIME Type:表示image/ipeg,video/*等媒體型別
匹配規則如下:
intent中的data必須和intent-filter完全匹配才能通過。有如下幾種情況:
a.intent沒有設定Uri和MIME Type,同時intent-filter也沒有設定
b.intent只包含Uri,但未包含MIME Type,同時能夠匹配上intent-filter設定的Uri,並且intent-filter為設定MIME Type
c.intent只設定MIME Type,同時intent-filter也設定了相同的MIME Type並且未指定Uri
d.intent設定了Uri和MIME Type,intent-filter只設定了MIME Type,則intent的Uri的scheme必須為content:或是file:。即,intent-filter如果沒有設定Uri,只設定了MIME Type,則Uri為content:或file:的模式。也就是說,過濾的規則希望元件能夠從檔案(file)或內容提供者(content provider)獲取到本地資料。
規則d例子,從相簿獲取圖片:
<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>複製程式碼
則intent的匹配規則為:
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("file://test"), "image/*");
startActivity(intent);複製程式碼
如果intent-filter設定了多個data,則intent中的data只要和其中一個匹配就可以通過
為了防止APP崩潰,所有的intent匹配規則進行呼叫前都要進行判斷處理:
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
本知識點完~