概述
Intent是用于和其他应用组件通信的消息对象,
通常有三种用途:启动Activity、启动Service、发送Broadcast
Intent类型
- 显式Intent
- 隐式Intent
创建Intent
-
Component name
- setComponent()
- setClass()
- setClassName()
-
Action
- ACTION_VIEW
- ACTION_SEND
-
Data
Uri对象、指定数据的MIME类型
- setDataAndType()
-
Category
- CATEGORY_BROWSABLE
- CATEGORY_LAUNCHER
-
Extras
Bundle键值对
-
Flags
指示如何启动Activity,以及启动后它所属的任务栈
示例: 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
清单文件中定义
-
-
-
PendingIntent
使用场景:
- Notification
- App Widget
- AlarmManager
创建:
- PendingIntent.getActivity()
- PendingIntent.getService()
- PendingIntent.getBroadcast()
解析Intent
-
action
Intent中指定的action必须与intent-filter中列出的action一项匹配。
若intent-filter中不包含action,匹配永远不会成功。
若Intent中未指定action,而只要intent-filter至少包含一个action就会默认匹配成功。
-
category
Intent中的每个category都必须与intent-filter中列出的category匹配。
即Intent中指定的category必须是intent-filter中category的子集。
若Intent不包含category,则匹配成功。
-
data
- 仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。
- 对于包含 URI 但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。
- 仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型但不含 URI 的 Intent 才会通过测试。
- 如果过滤器只是列出 MIME 类型,则假定组件支持
content:
和file:
数据。
Intent匹配
PackageManager
提供一整套query...()
方法来返回所有能够接受特定 Intent 的组件。此外,还会提供一系列类似的
resolve...()
方法来确定响应 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)
}
}
定时器
- 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)
}
}
相机
拍摄照片或视频
相对于相机应用,此界面只要拍摄功能,无相册
- 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.
启动相机应用
- INTENT_ACTION_STILL_IMAGE_CAMERA
- INTENT_ACTION_VIDEO_CAMERA
联系人
选择联系人
- Action:ACTION_PICK
- MIME Type:Contacts.CONTENT_TYPE
选择特定联系人数据
- 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 = 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
...
}
}
}
}
查看联系人
- Action:ACTION_VIEW
- Data URI:content:
fun viewContact(contactUri: Uri) {
val intent = Intent(Intent.ACTION_VIEW, contactUri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
编辑现有联系人
- Action:ACTION_EDIT
- Data URI:content:
- MIME Type:该类型是从联系人 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)
}
}
插入联系人
- 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)
}
}
电子邮件
文件存储
检索特定类型的文件
- Action:ACTION_GET_CONTENT
- MIME Type:文件对应类型
- 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:文件对应类型
-
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
显示给定经纬度地图
-
geo:latitude,longitude?z=zoom
按照特定缩放级别显示(1-23,1为全球地图,23为最高精度缩放)
-
geo:0,0?q=lat,lng(label)
显示给定经纬度处带字符串标签的地图
-
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:
- content:
- http:
- file:
- 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 打开拨号界面
- ACTION_CALL 拨打电话(需要CALL_PHONE权限)
- Data URI:
- tel:
- voicemail:
- tel:
fun dialPhoneNumber(phoneNumber: String) {
val intent = Intent(Intent.ACTION_DIAL).apply {
data = Uri.parse("tel:$phoneNumber")
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
网页搜索
- 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)
}
}
设置
- 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)
}
}
发短信
- Action:
- ACTION_SENDTO
- ACTION_SEND
- ACTION_SEND_MULTIPLE
- Data URI:
- sms:
- smsto:
- mms:
- mmsto:
- sms:
- 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)
}
}
网页浏览器
- Action:ACTION_VIEW
- Data URI:
- http:
- https:
- http:
- 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
使用adb调试Intent
adb shell am start -a -t -d \
-e -n
如:
adb shell am start -a android.intent.action.DIAL \
-d tel:555-5555 -n org.example.MyApp/.MyActivity