Intent和Intent过滤器

概述

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

    1. 仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。
    2. 对于包含 URI 但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。
    3. 仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型但不含 URI 的 Intent 才会通过测试。
    4. 如果过滤器只是列出 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:
  • 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:
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:
  • 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:
  • 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

你可能感兴趣的:(Intent和Intent过滤器)