启动 Activity 分为两种,显式调用和隐式调用。显式调用需要明确指出被启动组件的包名类名。隐式调用需要 Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息,如果不匹配将无法启动目标 Activity
一、IntentFilter 简介
- 意图过滤器的意思
- manifest文件中activity标签的子标签。
- IntentFilter 的过滤信息(子标签)有 action、category、data
1、IntentFilter 注意点
1、一个activity下可能有多个intentfilter,一个intent只要能匹配任何一组intentFilter下的信息便可成功启动activity。
2、一个intentFilter中action 、category、data都可以有多个。
3、想要隐式开启activity 必须在intentFilter添加 <category android:name=“android.intent.category.DEFAULT” />
二、Action规则
1、系统定义了一些Action字符串
<activity android:name=".MainActivity">
<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>
</activity>
2、我们也可以自定义Action字符串
<activity android:name=".ActivityC">
<intent-filter>
<action android:name="com.example.test" />//添加自定义字符串即可
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
3、Action匹配规则
1、intentFilter中的action可以有很多,只要intent添加的action和intentFilter中其中一个action匹配即可
2、action区分大小写,大小写不同的字符串是不同的action。
3、intentFilter 至少要有一个action
4、栗子
Intent intent = new Intent();
intent.setAction("com.example.test"); //intent 添加action。匹配intent-filter 下的一个action即可成功打开activity
startActivity(intent);
<activity android:name=".ActivityC">
<intent-filter>
<action android:name="com.example.test" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
三、Category规则
1、匹配规则
1、intentFilter中的category可以有很多,只要intent设置的category和intentFilter的匹配即可。
2、系统在调用startActivity或者startActivityForResult时,会默认为intent加上了android.intent.category.DEFAULT这个category。所以为了activity能够接受隐式调用必须在intentFilter下设置android.intent.category.DEFAULT。
2、栗子
mainactivity开启main2Activity。
#MainActivity
#main2activity的配置
#点击按钮(直接崩溃 如下)
找不到activity?我明明添加了action还和intentFilter下的其中一个action匹配,并且我添加了category也匹配了。这是为啥???还记得我们之前说过得系统在调用startActivity或者startActivityForResult时,默认为intent加上了android.intent.category.DEFAULT这个categor所以要想隐式开启activity这个categrory必须添加待intent-filter中。
Intent intent = new Intent();
intent.setAction("com.example.test1");
intent.addCategory(Intent.CATEGORY_DEFAULT); // 实际还有这个 系统封装在startActivity中了
intent.addCategory("com.example.category2");
startActivity(intent);
四、 data匹配规则
1、data简介
data由两部分组成mimeType和URI,语法如下。
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"/>
2、mimeType
1、媒体类型,如image/jpeg 、audio/mpeng4-generic、vodeo/* 可以表示图片文本视屏等不同媒体格式。
2、data 中可以不指定这个属性。
3、URI结构
1、scheme:URI的模式,比如http,file,content等字符串,此属性不可省略。
2、Host:URI的主机名比如 “www.baidu.com” ,此属性不可省略。
3、Port:URI中的端口号,比如80此属性可省略
4、parth ,pathPattern,pathPrefix 这三个参数表示路径信息。此属性可省略
4、栗子
<activity android:name=".SecActivity">
<!-- action 、category、data-->
<intent-filter>
<action android:name="aaa" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="secactivity"
android:scheme="test" />
</intent-filter>
</activity>
val intent = Intent()
intent.action = "aaa"
//这里可以不写CATEGORY_DEFAULT
// intent.addCategory(Intent.CATEGORY_DEFAULT) 系统在startActivity时会默认加上
intent.data = Uri.parse("test://secactivity")
startActivity(intent)
5、tips
1、URI是有默认值的。URI默认值为content或file。
2、如果需要为intent指定完整的data需要调用intent.setDataAndType(uri,type);这个方法,
3、setData 设置data的uri,setType 设置data的miniType但是 setData setType这两个方法彼此会清除对方值。(参考两个方法源码)
这样匹配规则就总结完了,另外注意intentFilter的匹配规则对Service,broadcastReceiver同样适用,不过系统对于Service的建议尽量使用显示意图来启动服务。
当组件设置了intent filter后便可支持隐式开启,这时exported属性默认会为true,组件支持外部应用开启。无intent filtre时组件的exported默认为false。
五、activity相关的常用方法
1、onNewIntent 触发条件有哪些?
1、activity 设置为SingleTop 且位于栈顶:再次开启activity会走 onNewIntent
2、activity设置为SingleTask、singleinstance任务栈中存在实例:再次开启activity会走onNewIntent
2、resolveActivity
避免找不到隐式activity而crash。注意参数PackageManager.MATH_DEFAULT_ONLY的使用。
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
startActivity(intent);
} else {
Toast.makeText(this, "Activity Not Found", Toast.LENGTH_SHORT).show();
}
4、异常状态下的数据恢复
onSaveInstanceState()
onRestoreInstanceState()
#思想:委托思想
首先 Activity 被意外终止时,Activity 会调用 onSaveInstanceState 去保存数据,然后 Activity 会委托 Window 去保存数据,接着 Window 在委托它上面的顶级容器再去一一通知它的子元素来保存数据,这样整个数据保存过程就完成了。
5、startActivityForResult使用
#mainActivity
...
...
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, 0x01);
...
...
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0x01 && resultCode == 0x02
&& data != null) {
// todo
}
}
#secondActivity
Intent intent = new Intent();
intent.putExtra("name", "i am second");
setResult(0x02, intent);
finish();