「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」
public class Intent implements Parcelable, Cloneable
1.Intent简介
Intent是一个经过序列化的消息传递对象,实现于Parcelable。应用于组件之间的交互与通信。 Intent负责对应用中的一次操作的action,catogary,data描述,系统会根据Intent的描述找到对应的组件完成组件的调用。基本用例包括以下三类:
-
启动 Activity
通过将 Intent 传递给 startActivity(),可以启动新的 Activity 实例。Intent 用于描述要启动的 Activity,并携带任何必要的数据。
如果希望在 Activity 完成后收到结果,请调用 startActivityForResult()。在Activity 的 onActivityResult() 回调中, Activity 将结果作为单独的 Intent 对象接收
-
启动服务
Service 是一个不使用用户界面而在后台执行操作的组件。使用 Android 5.0(API 级别 21)及更高版本,可以启动包含 JobScheduler 的服务。
对于 Android 5.0(API 级别 21)之前的版本,可以使用 Service 类的方法来启动服务。通过将 Intent 传递给 startService()或者bindService()
-
传递广播
广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将 Intent 传递给 sendBroadcast() 或 sendOrderedBroadcast(),可以将广播传递给其他应用。
Intent种类
Intent分为两种类型:
- 显示Intent 在我们startActivity()或者startService时构造的Intent对象时指定固定的类也就是我们能够提供类来构造ComponentName对象
下面是基于Android API 31源码中的两种构造方法
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
public @NonNull Intent setClass(@NonNull Context packageContext, @NonNull Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
return this;
}
*//使用
1.val intent = Intent(context,class)
或者
2.val intent = Intent()
intent.setClass(context,class)
startActivity(intent)*
- 隐式Intent 也就是不会指定特定的组件,需要配置IntentFilter来在AndroidManifest.xml中去匹配, 我们常用的是指定Action和包名来进行匹配。如果多个 IntentFilter兼容,则系统会显示一个对话框,支持用户选取要使用的应用。以下是谷哥官方图
隐式 Intent 如何通过系统传递以启动其他 Activity: [1] Activity A 创建包含操作描述的 Intent
,并将其传递给 startActivity()
。 [2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。找到匹配项之后, [3] 该系统通过调用匹配 Activity (Activity B) 的 onCreate()
方法并将其传递给 Intent
,以此启动匹配 Activity。
//使用方式
val intent = Intent()
intent.setPackage("com.stxx.newapp")
intent.action = "com.stxx.newapp.process"
//或者
//在构造函数中指定Action
val intent = Intent("com.stxx.newapp.process")
intent.setPackage("com.stxx.newapp")
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)
使用隐式Intent的注意事项:
使用隐式意图时要注意检查是否能够匹配上意图,否则会导致程序崩溃。我们可以使用Intent中的ResolveActivity()方法进行检查,如果结果不为null再进行startActivity()或者startService()操作
// 创建一个隐式Intent
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, textMessage)
type = "text/plain"
}
// 验证是否能够匹配,下面两种方法注意编译时API版本>30需要在manifest.xml中指定queries标签指定intent package,第三种方法则不需要
方法1:if (sendIntent.resolveActivity(packageManager) != null) {
startActivity(sendIntent)
}
方法2:if(packageManager.queryIntentActivities(sendIntent, MATCH_DEFAULT_ONLY)){
startActivity(sendIntent)
}
方法3:val info = packageManager.resolveActivity(sendIntent, MATCH_DEFAULT_ONLY)
if (info != null) {
startActivity(sendIntent)
} else {
toast("未匹配到组件")
}
如果有多个应用响应隐式 Intent,则用户可以选择要使用的应用,并将其设置为该操作的默认选项。如果用户可能希望每次使用相同的应用执行某项操作(例如,打开网页时,用户往往倾向于仅使用一种网络浏览器),则选择默认选项的功能十分有用。
但是,如果多个应用可以响应 Intent,且用户可能希望每次使用不同的应用,则应采用显式方式显示选择器对话框。选择器对话框会要求用户选择用于操作的应用(用户无法为该操作选择默认应用)。例如,当应用使用 ACTION_SEND
操作执行“共享”时,用户根据目前的状况可能需要使用另一不同的应用,因此应当始终使用选择器对话框,如图 2 中所示。
要显示选择器,请使用 createChooser()
创建 Intent
,并将其传递给 startActivity()
,如下例所示。此示例将显示一个对话框,其中有响应传递给 createChooser()
方法的 Intent 的应用列表,并且将提供的文本用作对话框标题。
val sendIntent = Intent(Intent.ACTION_SEND)
...
val title: String = resources.getString(R.string.chooser_title)
val chooser: Intent = Intent.createChooser(sendIntent, title)
if (sendIntent.resolveActivity(packageManager) != null) {
startActivity(chooser)
}
使用startActivity()启动隐式意图时,intent会默认添加一个android.intent.category.DEFAULT的category所以要注意在intent-filter中配置以下代码
<category android:name="android.intent.category.DEFAULT"/>
IntentFilter匹配规则
Intent对象大致包括7大属性:Action(动作) 、Data(数据) 、Category(类别) 、Type(数据类型) 、Component(组件) 、Extra(扩展信息) 、Flag(标志位) 。其中最常用的是Action属性和Data属性。
- Action: 定义匹配动作,属性值为一个字符串,Intent中必须携带有action,系统预定义了一些action,但是我们也可以在应用中定义自己的action。action元素可以声明多个。示例如下:
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>
Intent中必须指定action否则无法匹配任何组件。Intent中指定的action必须能在intent-filter中的某一项匹配
-
category Intent 过滤器既可以不声明任何
<category>
元素,也可以声明多个此类元素, 如果设置了intent-filter则必须设置《category android:name=”android.intent.category.DEFAULT”》原因前面已经说过。 还有在intent中设置的category必须和intent-filter中的某一项匹配。 Intent中如果不含任何category,则只匹配action即可。 -
Data 每个
<data>
元素均可指定 URI 结构和数据类型(MIME 媒体类型)。URI 的每个部分都是一个单独的属性:scheme
、host
、port
和path
:
<scheme>://<host>:<port>/<path>
过滤规则:
- 如果intent-filter中定义了data,那么Intent中必须也要携带可匹配的data反之如果未定义,intent中也不能携带
- 如果intent-filter未指定mimeType ,那么Intent中也不许指定否则无法匹配
- 当intent-filter列出相同的 MimeType且未指定 URI 格式时,包含MimeType但不含 URI 的 Intent 才会通过。 注意在Intent中同时设置data和type时 要使用setDataAndType()不可以分开调用setData()和setType().因为在单独调用每一个方法时都会把另一个参数 设置为null
public @NonNull Intent setData(@Nullable Uri data) {
mData = data;
mType = null;
return this;
}
下面是一个在浏览器中打开activity的示例:声明了两个过滤器。打开activity时只要命中一个即可
<activity
android:name=".view.start.LaunchActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/AppStartLoadTranslucent">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
//代表可以从浏览器中打开
<category android:name="android.intent.category.BROWSABLE" />
//声明了scheme为xjtmeeting;在js中只要调用[xjtmmeting://]的url就可以打开该activity
<data android:scheme="xjtmeeting" />
</intent-filter>
今天的文章Intent和IntentFilter分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14855.html