Intent相关
一、定义
消息传递的对象,可以用来从其他应用组件请求操作,基本用例如下:
- 启动Activity
-
startActivity() 启动新的activity,其中intent可以携带相应的数据,但是携带数据必须可序列化,String和基本数据类型。同时数据携带有大小限制,具体限制大小可以查看该网址
Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent);
-
startActivityForResult() 启动新的Acitivity并在新页面返回时候,可携带部分数据返回。注意①如果跳转前页面为fragment,必须重写它依赖的Activity或者父类fragment,否则会出现接收不了情况 ②如果所在fragment在viewpager下,不仅应该重写Acitity,而且应该区别处理回调处理,防止所有fragment收到相关回调。
Intent intent = new Intent(this, SecondActivity.class); startActivityForResult(intent, REQUEST_CODE);
- 启动服务
- 对于API 21之前的版本,可以用intent.startService()来启动服务
- 服务旨在使用客户端-服务端接口,通过bindService()将intent传递
-
传递广播
启动广播,sendBroadCast()或者sendOrderBroadCast()将intent传递给广播接收者
二、Intent类型
1.显示调用
通过目标的包名称或者组件名称,启动相应组件。
// 使用构造函数,传入context,class
// Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Intent intent = new Intent();
//使用className来
intent.setClassName(MainActivity.this, "com.yobin.testintent.SecondActivity");
startActivity(intent);
2.隐式调用
不会指定特定的组件,只是声明常规操作,从而允许其他应用中的组件来处理
三、构建Intent
-
action
指定要执行的通用操作的字符串,很大程度决定其余Intent的构成,特别是数据和extra中包含的内容。通常的操作常量ACTION_VIEW(向用户显示信息), ACTION_SEND(向用户共享数据)
-
data
-
type
data是Uri类型数据,type是数据MIME类型,指定数据的MIME类型数据有助于Android系统找到接收Intent的最佳组件
注意:调用setData和调用setType不能同时调用,因为会互相抵消彼此的值,如果需要设置用setDataAndType()同时设置URI和MIME类型
private String getMIMEType(File file) { String type = "*/*"; String fName = file.getName(); // 获取后缀名前的分隔符"."在fName中的位置。 int dotIndex = fName.lastIndexOf("."); if (dotIndex < 0) { return type; } /* 获取文件的后缀名 */ String end = fName.substring(dotIndex, fName.length()).toLowerCase(); if (end == "") return type; // 在MIME和文件类型的匹配表中找到对应的MIME类型。 for (int i = 0; i < MIME_MapTable.length; i++) { if (end.equals(MIME_MapTable[i][0])) type = MIME_MapTable[i][1]; } return type; } private final String[][] MIME_MapTable = { //名称后缀和MIME类型 // {后缀名,MIME类型} {".3gp", "video/3gpp"}, {".apk", "application/vnd.android.package-archive"}, {".asf", "video/x-ms-asf"}, {".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"}, {".bmp", "image/bmp"}, {".c", "text/plain"}, {".class", "application/octet-stream"}, {".conf", "text/plain"}, {".cpp", "text/plain"}, {".doc", "application/msword"}, {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {".xls", "application/vnd.ms-excel"}, {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {".exe", "application/octet-stream"}, {".gif", "image/gif"}, {".gtar", "application/x-gtar"}, {".gz", "application/x-gzip"}, {".h", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".jar", "application/java-archive"}, {".java", "text/plain"}, {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".js", "application/x-javascript"}, {".log", "text/plain"}, {".m3u", "audio/x-mpegurl"}, {".m4a", "audio/mp4a-latm"}, {".m4b", "audio/mp4a-latm"}, {".m4p", "audio/mp4a-latm"}, {".m4u", "video/vnd.mpegurl"}, {".m4v", "video/x-m4v"}, {".mov", "video/quicktime"}, {".mp2", "audio/x-mpeg"}, {".mp3", "audio/x-mpeg"}, {".mp4", "video/mp4"}, {".mpc", "application/vnd.mpohun.certificate"}, {".mpe", "video/mpeg"}, {".mpeg", "video/mpeg"}, {".mpg", "video/mpeg"}, {".mpg4", "video/mp4"}, {".mpga", "audio/mpeg"}, {".msg", "application/vnd.ms-outlook"}, {".ogg", "audio/ogg"}, {".pdf", "application/pdf"}, {".png", "image/png"}, {".pps", "application/vnd.ms-powerpoint"}, {".ppt", "application/vnd.ms-powerpoint"}, {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {".prop", "text/plain"}, {".rc", "text/plain"}, {".rmvb", "audio/x-pn-realaudio"}, {".rtf", "application/rtf"}, {".sh", "text/plain"}, {".tar", "application/x-tar"}, {".tgz", "application/x-compressed"}, {".txt", "text/plain"}, {".wav", "audio/x-wav"}, {".wma", "audio/x-ms-wma"}, {".wmv", "audio/x-ms-wmv"}, {".wps", "application/vnd.ms-works"}, {".xml", "text/plain"}, {".z", "application/x-compress"}, {".zip", "application/x-zip-compressed"}, {"", "*/*"}}; Uri data; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { data = FileProvider7.getUriForFile(getContext(), file); // 给目标应用一个临时授权 openintent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { data = Uri.fromFile(file); } String type = getMIMEType(file); // 设置intent的data和Type属性。 openintent.setDataAndType(/* uri */data, type);
-
Catgory
指定当前动作被执行的环境
① CATGORY_lAUNCHER 该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。
② CATGORY_BROWSABLE 设置组件可以使用浏览器启动,表示该activity只能用来浏览网页
③ CATGORY_DEFULT:android 默认执行方式,所有的Intent都可以激活它
-
Extra
携带数据请求
//跳转到网页 Intent intent = new Intent(); intent.setData(Uri.parse("http://www.baidu.com")); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_BROWSABLE); startActivity(intent); //跳转地图 Intent mapIntent = new Intent(); mapIntent.setData(Uri.parse("geo:38.899533,-77.036476")); mapIntent.setAction(Intent.ACTION_VIEW); mapIntent.addCategory(Intent.CATEGORY_BROWSABLE); startActivity(mapIntent); //拨打电话-调用拨号盘 Intent telIntent = new Intent(); telIntent.setData(Uri.parse("tel:18210165501")); telIntent.setAction(Intent.ACTION_DIAL); startActivity(telIntent); //拨打电话-直接拨号 //要使用这个必须在配置文件中加入<uses-permission android:name="android.permission.CALL_PHONE"/> //需要动态调用相关权限,不能仅仅在manifest中声明 Intent telIIntent = new Intent(); telIIntent.setData(Uri.parse("tel:18210165501")); telIIntent.setAction(Intent.ACTION_CALL); startActivity(telIIntent); //调用发送短信程序(方法一) Uri uri = Uri.parse("smsto:15980665805"); Intent intent = new Intent(Intent.ACTION_SENDTO, uri); intent.putExtra("sms_body", "The SMS text"); startActivity(intent); //调用发送短信程序(方法二) Intent intent = new Intent(Intent.ACTION_VIEW); intent.putExtra("sms_body", "The SMS text"); intent.setType("vnd.android-dir/mms-sms"); startActivity(intent); //发送彩信 Uri uri = Uri.parse("content://media/external/images/media/23"); Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra("sms_body", "some text"); intent.putExtra(Intent.EXTRA_STREAM, uri); intent.setType("image/png"); startActivity(intent); //发送Email(方法一)(要在 Android 手机上才能测试) Uri uri = Uri.parse("mailto:zhangsan@gmail.com"); Intent intent = new Intent(Intent.ACTION_SENDTO, uri); startActivity(intent); //发送Email(方法二)(要在 Android 手机上才能测试) Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setData(Uri.parse("mailto:zhangsan@gmail.com")); intent.putExtra(Intent.EXTRA_SUBJECT, "这是标题"); intent.putExtra(Intent.EXTRA_TEXT, "这是内容"); startActivity(intent); //发送Email(方法三)(要在 Android 手机上才能测试) Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, "me@abc.com"); intent.putExtra(Intent.EXTRA_SUBJECT, "这是标题"); intent.putExtra(Intent.EXTRA_TEXT, "这是内容"); intent.setType("text/plain"); //选择一个邮件客户端 startActivity(Intent.createChooser(intent, "Choose Email Client")); // 发送Email(方法四)(要在 Android 手机上才能测试) Intent intent = new Intent(Intent.ACTION_SEND); //收件人 String[] tos = {"to1@abc.com", "to2@abc.com"}; //抄送人 String[] ccs = {"cc1@abc.com", "cc2@abc.com"}; //密送人 String[] bcc = {"bcc1@abc.com", "bcc2@abc.com"}; intent.putExtra(Intent.EXTRA_EMAIL, tos); intent.putExtra(Intent.EXTRA_CC, ccs); intent.putExtra(Intent.EXTRA_BCC, bcc); intent.putExtra(Intent.EXTRA_SUBJECT, "这是标题"); intent.putExtra(Intent.EXTRA_TEXT, "这是内容"); intent.setType("message/rfc822"); startActivity(Intent.createChooser(intent, "Choose Email Client")); //发送Email且发送附件(要在 Android 手机上才能测试) Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); intent.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mp3/醉红颜.mp3"); intent.setType("audio/mp3"); startActivity(Intent.createChooser(intent, "Choose Email Client")); //播放媒体文件(android 对中文名的文件支持不好) Intent intent = new Intent(Intent.ACTION_VIEW); //Uri uri = Uri.parse("file:///sdcard/zhy.mp3"); Uri uri = Uri.parse("file:///sdcard/a.mp3"); intent.setDataAndType(uri, "audio/mp3"); startActivity(intent); Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent) Intent intent2 = new Intent(Intent.ACTION_CHOOSER); intent2.putExtra(Intent.EXTRA_INTENT, intent1); intent2.putExtra(Intent.EXTRA_TITLE, "aaaa"); startActivity(intent2); //设置壁纸 Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER); startActivity(Intent.createChooser(intent, "设置壁纸")); //卸载APK //fromParts方法 //参数1:URI 的 scheme //参数2:包路径 //参数3: Uri uri = Uri.fromParts("package", "com.yobin.testintent", null); Intent intent = new Intent(Intent.ACTION_DELETE, uri); startActivity(intent); //安装APK(???) Uri uri = Uri.fromParts("package", "com.great.activity_intent", null); Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED, uri); startActivity(intent); //调用搜索 Intent intent = new Intent(); intent.setAction(Intent.ACTION_WEB_SEARCH); intent.putExtra(SearchManager.QUERY, "android"); startActivity(intent);
四、CreateChooser()的作用
-
如果有多个应用可以响应Intent,选择要使用的应用后,并设置默认选项后,那么每次都会执行该默认操作,但是如果用户希望每次使用不同应用,用createChooser()可以强制显示选择对话框,并且无法设置默认操作。
Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, "你好,是什么出现"); sendIntent.setType("text/plain"); //发送短信 Intent chooseIntent = Intent.createChooser(sendIntent, "这是选择的应用"); //包裹原始intent if (chooseIntent.resolveActivity(getPackageManager()) != null) {//判断该intent是否有activity意图 startActivity(chooseIntent); }
-
如果没有应用响应,使用原始的startActivtiy,如果没有去resolveActivty方法判断,会抛出ActivityNotFoundException,而用createChooser会显示无应用可以执行操作
-
用于过滤不需要的应用显示在弹窗中
public void clickView(View view) { Intent sendIntent = getIntent(); //遍历查询所有可以打开页面信息 List<ResolveInfo> resolveInfosNew = context.getPackageManager().queryIntentActivities(sendIntent, 0); List<Intent> targetIntents = new ArrayList<>(); if (!resolveInfosNew.isEmpty()) { for (ResolveInfo resolveInfo : resolveInfosNew) { ActivityInfo activityInfo = resolveInfo.activityInfo; String packageName = activityInfo.packageName; //可以利用packageName来进行过滤 if (!packageName.equals("com.android.bluetooth")) { //需要过滤的蓝牙 Intent intent = getIntent(); intent.setComponent(new ComponentName(packageName, activityInfo.name));//设置组件信息 targetIntents.add(intent); } } } if (targetIntents.size() > 0) { Intent chooseIntent = Intent.createChooser(new Intent(), "这是选择的应用"); //包裹实际的应用 //将需要的intent加入到chooseIntent中 chooseIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{})); if (chooseIntent.resolveActivity(getPackageManager()) != null) { //解析是否有intent对应的activity. startActivity(chooseIntent); } } } public Intent getIntent() { //需要加载的意图 Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, "你好呢,哈哈"); intent.setType("text/plain"); return intent; }
五、接收隐式Intent
要公布应用可以接收哪些隐式Intent,需要在清单文件中使用intent-filter元素为每个应用组件声明一个或多个Intent过滤器,每个过滤器可以有<action>,<data>,<category>三个组成
-
<action> 声明可以接收的操作,可以自定义,但是该值必须是操作的文本字符串,不可以是类常量
-
<data> 使用一个或多个指定数据URI(scheme、host、port、path),各个方面和MIME类型属性,声明接收的数据类型。
注意:每个<data>元素均可以指定URI结构和数据类型,URI包括scheme、host、port、path
<scheme>://<host>:<port>/<path>
content://com.yobin.project:200/folder/subfolder/etc 架构<scheme>:content 主机<host>:com.yobin.project 端口<port>:200 路径<path>:folder/subfolder/etc 上述属性存在依赖关系 1. 如果没有指定架构,就忽略主机 2. 没有指定主机,忽略端口 3. 未指定主机和架构,忽略路径 当Intent中URI与过滤器中URI规范进行比较时候,仅与过滤器包含的部分URI进行比较 1. 如果过滤器仅指定架构,则具有该架构的所有URI均与过滤器匹配 2. 如果过滤器指定架构和权限,但未指定路径,则具有相同架构和权限的所有 URI 都会通过过滤器,无论其路径如何均是如此 3. 如果过滤器指定架构、权限和路径,则仅具有相同架构、权限和路径的 URI 才会通过过滤器 注意: 路径规范可以包含星号通配符 (*),因此仅需部分匹配路径名即可 数据测试会将 Intent 中的 URI 和 MIME 类型与过滤器中指定的 URI 和 MIME 类型进行比较。规则如下: 1. 仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。 2. 对于包含 URI 但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指 定 MIME 类型时,才会通过测试。 3.仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型但不含 URI 的 Intent 才会通过测试。 4.仅当 MIME 类型与过滤器中列出的类型匹配时,同时包含 URI 类型和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果 Intent 具有 content: 或 file: URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。换言之,如果过滤器只是列出 MIME 类型,则假定组件支持 content: 和 file: 数据 注意:指定了Intent的URI和MIME类型,如果数据中没有<data>,则匹配失败。
- <category> name属性中声明接收类别,必须是可以操作的文本字符串值,不能为常量。注意,接收隐式Intent必须将CATEGORY_DEFAULT类别包括在Intent过滤器中,startActivity()和startActivityForResult()将按照其声明类别处理所有Intent,如果没有此声明,那么隐式Intent不会解析Activity.
<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>
注意
本文是来源是Android开发者网站,以及部分网址,进行了相关的整理,增加了部分自己的东西。