阅读 197

Intent和IntentFilter

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分为两种类型:

  1. 显示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)*复制代码
  1. 隐式Intent

也就是不会指定特定的组件,需要配置IntentFilter来在AndroidManifest.xml中去匹配, 我们常用的是指定Action和包名来进行匹配。如果多个 IntentFilter兼容,则系统会显示一个对话框,支持用户选取要使用的应用。以下是谷哥官方图

intent-filters_2x.png隐式 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 的每个部分都是一个单独的属性:schemehostport 和 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>


作者:fighter_
链接:https://juejin.cn/post/7031459769932054565

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐