概述
Intent是用于和其他應(yīng)用組件通信的消息對(duì)象,
通常有三種用途:啟動(dòng)Activity啸罢、啟動(dòng)Service裳朋、發(fā)送Broadcast
Intent類型
- 顯式Intent
- 隱式Intent
創(chuàng)建Intent
-
Component name
- setComponent()
- setClass()
- setClassName()
-
Action
- ACTION_VIEW
- ACTION_SEND
-
Data
Uri對(duì)象、指定數(shù)據(jù)的MIME類型
- setDataAndType()
-
Category
- CATEGORY_BROWSABLE
- CATEGORY_LAUNCHER
-
Extras
Bundle鍵值對(duì)
-
Flags
指示如何啟動(dòng)Activity温学,以及啟動(dòng)后它所屬的任務(wù)棧
示例: App選擇器
val sendIntent = Intent(Intent.ACTION_SEND)
...
// Always use string resources for UI text.
// This says something like "Share this photo with"
val title: String = resources.getString(R.string.chooser_title)
// Create intent to show the chooser dialog
val chooser: Intent = Intent.createChooser(sendIntent, title)
// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(packageManager) != null) {
startActivity(chooser)
}
接收隱式Intent
清單文件中定義<intent-filter>
- <action>
- <data>
- <category>
<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
使用場景:
- Notification
- App Widget
- AlarmManager
創(chuàng)建:
- PendingIntent.getActivity()
- PendingIntent.getService()
- PendingIntent.getBroadcast()
<font color="red">解析Intent</font>
-
action
Intent中指定的action必須與intent-filter中列出的action一項(xiàng)匹配聪建。
若intent-filter中不包含action钙畔,匹配永遠(yuǎn)不會(huì)成功。
若Intent中未指定action金麸,而只要intent-filter至少包含一個(gè)action就會(huì)默認(rèn)匹配成功擎析。
-
category
Intent中的每個(gè)category都必須與intent-filter中列出的category匹配。
即Intent中指定的category必須是intent-filter中category的子集挥下。
若Intent不包含category揍魂,則匹配成功。
-
data
- 僅當(dāng)過濾器未指定任何 URI 或 MIME 類型時(shí)棚瘟,不含 URI 和 MIME 類型的 Intent 才會(huì)通過測試现斋。
- 對(duì)于包含 URI 但不含 MIME 類型(既未顯式聲明,也無法通過 URI 推斷得出)的 Intent偎蘸,僅當(dāng)其 URI 與過濾器的 URI 格式匹配庄蹋、且過濾器同樣未指定 MIME 類型時(shí),才會(huì)通過測試迷雪。
- 僅當(dāng)過濾器列出相同的 MIME 類型且未指定 URI 格式時(shí)限书,包含 MIME 類型但不含 URI 的 Intent 才會(huì)通過測試。
- 如果過濾器只是列出 MIME 類型章咧,則假定組件支持
content:
和file:
數(shù)據(jù)倦西。
Intent匹配
PackageManager
提供一整套query...()
方法來返回所有能夠接受特定 Intent 的組件。此外赁严,還會(huì)提供一系列類似的
resolve...()
方法來確定響應(yīng) Intent 的最佳組件扰柠。
常見Intent
鬧鐘
- Action:ACTION_SET_ALARM
- Extras
- EXTRA_HOUR
- EXTRA_MINUTES
- EXTRA_MESSAGE
- EXTRA_DAYS
- EXTRA_RINGTONE
- EXTRA_VIBRATE
- EXTRA_SKIP_UI
//SET_ALARM permission
fun createAlarm(message: String, hour: Int, minutes: Int) {
val intent = Intent(AlarmClock.ACTION_SET_ALARM).apply {
putExtra(AlarmClock.EXTRA_MESSAGE, message)
putExtra(AlarmClock.EXTRA_HOUR, hour)
putExtra(AlarmClock.EXTRA_MINUTES, minutes)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
定時(shí)器
- Action:ACTION_SET_TIMER
- Extras:
- EXTRA_LENGTH
- EXTRA_MESSAGE
- EXTRA_SKIP_UI
//SET_ALARM permission
fun startTimer(message: String, seconds: Int) {
val intent = Intent(AlarmClock.ACTION_SET_TIMER).apply {
putExtra(AlarmClock.EXTRA_MESSAGE, message)
putExtra(AlarmClock.EXTRA_LENGTH, seconds)
putExtra(AlarmClock.EXTRA_SKIP_UI, true)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
顯示所有鬧鐘
- Action:ACTION_SHOW_ALARMS
日歷
- Action:ACTION_INSERT
- Data URI:Events.CONTENT_URI
- MIME Type:“vnd.android.cursor.dir/event”
- Extra:
- EXTRA_EVENT_ALL_DAY
- EXTRA_EVENT_BEGIN_TIME
- EXTRA_EVENT_END_TIME
- TITLE
- DESCRIPTION
- EVENT_LOCATION
- EXTRA_EMAIL
fun addEvent(title: String, location: String, begin: Long, end: Long) {
val intent = Intent(Intent.ACTION_INSERT).apply {
data = Events.CONTENT_URI
putExtra(Events.TITLE, title)
putExtra(Events.EVENT_LOCATION, location)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
相機(jī)
拍攝照片或視頻
相對(duì)于相機(jī)應(yīng)用粉铐,此界面只要拍攝功能,無相冊
- Action:ACTION_IMAGE_CAPTURE or ACTION_VIDEO_CAPTURE
- Extras:EXTRA_OUTPUT
const val REQUEST_IMAGE_CAPTURE = 1
val locationForPhotos: Uri = ...
fun capturePhoto(targetFilename: String) {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
putExtra(MediaStore.EXTRA_OUTPUT, Uri.withAppendedPath(locationForPhotos, targetFilename))
}
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
val thumbnail: Bitmap = data.getParcelableExtra("data")
// Do other work with full size photo saved in locationForPhotos
...
}
}
For more information about how to use this intent to capture a photo, including how to create an appropriate
Uri
for the output location, read Taking Photos Simply or Taking Videos Simply.
啟動(dòng)相機(jī)應(yīng)用
- INTENT_ACTION_STILL_IMAGE_CAMERA
- INTENT_ACTION_VIDEO_CAMERA
聯(lián)系人
選擇聯(lián)系人
- Action:ACTION_PICK
- MIME Type:Contacts.CONTENT_TYPE
選擇特定聯(lián)系人數(shù)據(jù)
- Action:ACTION_PICK
- MIME Type:
- CommonDataKinds.Phone.CONTNET_TYPE
- CommonDataKinds.Email.CONTNET_TYPE
const val REQUEST_SELECT_PHONE_NUMBER = 1
fun selectContact() {
// Start an activity for the user to pick a phone number from contacts
val intent = Intent(Intent.ACTION_PICK).apply {
type = CommonDataKinds.Phone.CONTENT_TYPE
}
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == Activity.RESULT_OK) {
// Get the URI and query the content provider for the phone number
val contactUri: Uri = data.data
val projection: Array<String> = arrayOf(CommonDataKinds.Phone.NUMBER)
contentResolver.query(contactUri, projection, null, null, null).use { cursor ->
// If the cursor returned is valid, get the phone number
if (cursor.moveToFirst()) {
val numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER)
val number = cursor.getString(numberIndex)
// Do something with the phone number
...
}
}
}
}
查看聯(lián)系人
- Action:ACTION_VIEW
- Data URI:content:<URI>
fun viewContact(contactUri: Uri) {
val intent = Intent(Intent.ACTION_VIEW, contactUri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
編輯現(xiàn)有聯(lián)系人
- Action:ACTION_EDIT
- Data URI:content:<URI>
- MIME Type:該類型是從聯(lián)系人 URI 推斷得出
- Extra:ContactsContract.Intents.Insert
fun editContact(contactUri: Uri, email: String) {
val intent = Intent(Intent.ACTION_EDIT).apply {
data = contactUri
putExtra(ContactsContract.Intents.Insert.EMAIL, email)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
插入聯(lián)系人
- Action:ACTION_INSERT
- MIME Type:Contacts.CONTENT_TYPE
- Extra:ContactsContract.Intents.Insert
fun insertContact(name: String, email: String) {
val intent = Intent(Intent.ACTION_INSERT).apply {
type = ContactsContract.Contacts.CONTENT_TYPE
putExtra(ContactsContract.Intents.Insert.NAME, name)
putExtra(ContactsContract.Intents.Insert.EMAIL, email)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
電子郵件
文件存儲(chǔ)
檢索特定類型的文件
- Action:ACTION_GET_CONTENT
- MIME Type:文件對(duì)應(yīng)類型
- Extra:
- EXTRA_ALLOW_MULTIPLE
- EXTRA_LOCAL_ONLY
- Category(可選):CATEGORY_OPENABLE
//獲取照片
const val REQUEST_IMAGE_GET = 1
fun selectImage() {
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "image/*"
}
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(intent, REQUEST_IMAGE_GET)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_IMAGE_GET && resultCode == Activity.RESULT_OK) {
val thumbnail: Bitmap = data.getParcelableExtra("data")
val fullPhotoUri: Uri = data.data
// Do work with photo saved at fullPhotoUri
...
}
}
打開特定類型的文件
Action:ACTION_OPEN_DOCUMENT or ACTION_CREATE_DOCUMENT
MIME Type:文件對(duì)應(yīng)類型
-
Extra:
- EXTRA_MIME_TYPES
- EXTRA_ALLOW_MULTIPLE
- EXTRA_TITLE
- EXTRA_LOCAL_ONLY
Category:CATEGORY_OPENABLE
//獲取照片2
const val REQUEST_IMAGE_OPEN = 1
fun selectImage2() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
type = "image/*"
addCategory(Intent.CATEGORY_OPENABLE)
}
// Only the system receives the ACTION_OPEN_DOCUMENT, so no need to test.
startActivityForResult(intent, REQUEST_IMAGE_OPEN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_IMAGE_OPEN && resultCode == Activity.RESULT_OK) {
val fullPhotoUri: Uri = data.data
// Do work with full size photo saved at fullPhotoUri
...
}
}
地圖
Action:ACTION_VIEW
-
Data URI:
-
geo:latitude,longitude
顯示給定經(jīng)緯度地圖
-
geo:latitude,longitude?z=zoom
按照特定縮放級(jí)別顯示(1-23耻矮,1為全球地圖秦躯,23為最高精度縮放)
-
geo:0,0?q=lat,lng(label)
顯示給定經(jīng)緯度處帶字符串標(biāo)簽的地圖
-
geo:0,0?q=my+street+address
顯示“我的街道”位置
-
fun showMap(geoLocation: Uri) {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = geoLocation
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
音樂或視頻
播放媒體文件
- Action:ACTION_VIEW
- Data URI:
- file:<URI>
- content:<URI>
- http:<URI>
- MIME Type:
- "audio/*"
- "application/ogg"
- "application/x-ogg"
- "application/itunes"
fun playMedia(file: Uri) {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = file
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
基于搜索播放音樂
- Action:INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- Extra:MediaStore.EXTRA_MEDIA_FOCUS
fun playSearchArtist(artist: String) {
val intent = Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH).apply {
putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)
putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist)
putExtra(SearchManager.QUERY, artist)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
新筆記
- Action:ACTION_CREATE_NOTE
- MIME Type:PLAIN_TEXT_TYPE
- Extra:
- EXTRA_NAME
- EXTRA_TEXT
fun createNote(subject: String, text: String) {
val intent = Intent(NoteIntents.ACTION_CREATE_NOTE).apply {
putExtra(NoteIntents.EXTRA_NAME, subject)
putExtra(NoteIntents.EXTRA_TEXT, text)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
電話
- Action:
- ACTION_DIAL 打開撥號(hào)界面
- ACTION_CALL 撥打電話(需要CALL_PHONE權(quán)限)
- Data URI:
- tel:<phone-number>
- voicemail:<phone-number>
fun dialPhoneNumber(phoneNumber: String) {
val intent = Intent(Intent.ACTION_DIAL).apply {
data = Uri.parse("tel:$phoneNumber")
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
網(wǎng)頁搜索
- Action:ACTION_WEB_SEARCH
- Extra:SearchManager.QUERY 搜索字符串
fun searchWeb(query: String) {
val intent = Intent(Intent.ACTION_WEB_SEARCH).apply {
putExtra(SearchManager.QUERY, query)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
設(shè)置
- Action:
- ACTION_SETTINGS
- ACTION_WIRELESS_SETTINGS
- ACTION_AIRPLANE_MODE_SETTINGS
- ACTION_WIFI_SETTINGS
- ACTION_APN_SETTINGS
- ACTION_BLUETOOTH_SETTINGS
- ACTION_DATE_SETTINGS
- ACTION_LOCALE_SETTINGS
- ACTION_INPUT_METHOD_SETTINGS
- ACTION_DISPLAY_SETTINGS
- ACTION_SECURITY_SETTINGS
- ACTION_LOCATION_SOURCE_SETTINGS
- ACTION_INTERNAL_STORAGE_SETTINGS
- ACTION_MEMORY_CARD_SETTINGS
fun openWifiSettings() {
val intent = Intent(Settings.ACTION_WIFI_SETTINGS)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
發(fā)短信
- Action:
- ACTION_SENDTO
- ACTION_SEND
- ACTION_SEND_MULTIPLE
- Data URI:
- sms:<phone_number>
- smsto:<phone_number>
- mms:<phone_number>
- mmsto:<phone_number>
- MIME Type:
- "text/plain"
- "image/*"
- "video/*"
- Extra
- "subject"
- "sms_body"
- EXTRA_STREAM
fun composeMmsMessage(message: String, attachment: Uri) {
val intent = Intent(Intent.ACTION_SEND).apply {
data = Uri.parse("smsto:") // This ensures only SMS apps respond
putExtra("sms_body", message)
putExtra(Intent.EXTRA_STREAM, attachment)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
網(wǎng)頁瀏覽器
- Action:ACTION_VIEW
- Data URI:
- http:<URL>
- https:<URL>
- MIME Type:
- "text/plain"
- "text/html"
- "application/xhtml+xml"
- "application/vnd.wap.xhtml+xml"
fun openWebPage(url: String) {
val webpage: Uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, webpage)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
示例intent-filter
<activity ...>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<!-- Include the host attribute if you want your app to respond
only to URLs with your app's domain. -->
<data android:scheme="http" android:host="www.example.com" />
<category android:name="android.intent.category.DEFAULT" />
<!-- The BROWSABLE category is required to get links from web pages. -->
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
使用adb調(diào)試Intent
adb shell am start -a <ACTION> -t <MIME_TYPE> -d <DATA> \
-e <EXTRA_NAME> <EXTRA_VALUE> -n <ACTIVITY>
如:
adb shell am start -a android.intent.action.DIAL \
-d tel:555-5555 -n org.example.MyApp/.MyActivity