上一篇详细讲解了Intent用于启动三个属性:Component、Action和Category。那么这一篇将会把剩下的4个属性:Date、Type、Extra和Flag详细讲解一遍,用来加深自己对Intent的了解和记忆。
*******************************************
二、Intent传递数据
我们可以通过Intent的Data、Type、Extra传入一些数据,这些数据可以用于进一步筛选匹配Activity,打开指定的页面、文件,或者给准备启动的Activity传入需要的参数。
1.Data
1.1 Data接收的Uri对象格式
Data属性用来向Action提供用于操作的数据。setData语句令Data接收一个Uri对象,Uri对象内容通常为这个格式:
<scheme>://<host>:<port>/<path>
也就是:<协议>://<主机名>:<端口号>/<路径>
例如:http://www.tahlia.com:8888/test
<android:scheme——http>://<android:host——www.tahlia.com>:<android:port——8888>/<android:path——test>
或者file://com.example.tahlia.exercise/test/1
<android:scheme——file>://<android:host——com.example.tahlia.exercise>/<android:path——test/1> (此处省略了端口号)
1.2 Data的匹配规则
Data的匹配规则和action有点像,但是匹配的顺序是相反的。回忆一下,action是先接收传入的action字符串,然后Android会在intent-filter过滤器中寻找是否有相匹配的组件。而data则是先在组件之中设定data的属性值(如规定协议为http、规定端口号为8888等),在接收到外界启动这个组件的要求时检查是否传入对应的属性值。如果属性值相同,则启动;属性值不同,则无法启动。用一张图来理顺一下action和data的匹配顺序区别:
※ 这里要注意的是,使用intent可能会隐式启动多个组件,而每个组件都会进行setData进行匹配,最后再获得所有能够被启动的组件,提供给用户进行选择。如果最后并没有获得可以被启动的组件,则会抛出ActivityNotFoundException。
用一段代码来加深一下data的匹配规则:新建4个Activity,分别命名为Aty1,Aty2,Aty3,Aty4。在mainifest中为他们配置相同的action用于隐式启动,配置不同的data,如下:
<activity android:name=".Aty1"
android:label="Aty1">
<intent-filter>
<action android:name="com.example.tahlia.intent_exercise_04.intent.android.Aty"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
<activity android:name=".Aty2"
android:label="Aty2">
<intent-filter>
<action android:name="com.example.tahlia.intent_exercise_04.intent.android.Aty"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:scheme="http"
android:host="www.baidu.com"/>
</intent-filter>
</activity>
<activity android:name=".Aty3"
android:label="Aty3">
<intent-filter>
<action android:name="com.example.tahlia.intent_exercise_04.intent.android.Aty"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:scheme="http"
android:host="www.baidu.com"
android:port="8888"/>
</intent-filter>
</activity>
<activity android:name=".Aty4"
android:label="Aty4">
<intent-filter>
<action android:name="com.example.tahlia.intent_exercise_04.intent.android.Aty"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:scheme="http"
android:host="www.baidu.com"
android:port="8888"
android:path="/mypath"/>
</intent-filter>
</activity>
这里分别设置了Aty1、Aty2、Aty3、Aty4的不同的data子元素。相对应的,也就设定了intent.setData的Uri对象所包含的启动不同Activity的条件,如下:
当Uri对象的scheme为http时,就能启动Aty1;
当Uri对象的scheme为http,host为www.baidu.com时,就能启动Aty2;
当Uri对象的scheme为http,host为www.baidu.com,port为8888时,就能启动Aty3;
当Uri对象的scheme为http,host为www.baidu.com,port为8888,path为/mypath时,就能启动Ath4。
MainActivity布局如下:
在MainActivity中注册监听函数,将对应的Uri对象添加如下:
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.tahlia.intent_exercise_04.intent.android.Aty");
switch(view.getId()){
case R.id.Btn1:
intent.setData(Uri.parse("http://www.abdcefg.com:1234/test"));
startActivity(intent);
break;
case R.id.Btn2:
intent.setData(Uri.parse("http://www.baidu.com:1234/test"));
startActivity(intent);
break;
case R.id.Btn3:
intent.setData(Uri.parse("http://www.baidu.com:8888/test"));
startActivity(intent);
break;
case R.id.Btn4:
intent.setData(Uri.parse("http://www.baidu.com:8888/mypath"));
startActivity(intent);
break;
}
}
运行一下看看效果:
从上面结果可以看出,data的匹配规则是和action完全相反的,匹配规则不由intent决定,而是由被启动组件的data子元素决定。如果看到这里,还是拐不过弯去理解这个匹配规则的话,可以试试使用以下这个表格来确定到底是否能匹配成功:
→:data的限制条件 | Aty1的data子项内容 | Aty2的data子项内容 | Aty3的data子项内容 | Aty4的data子项内容 |
↓:待判断的Uri对象 | scheme:http | scheme:http host:www.baidu.com | scheme:http host:www.baidu.com port:8888 | scheme:http host:www.baidu.com port:8888 path:/mypath |
http:www.abcdefg.com:1234/test | 满足 | 不满足 | 不满足 | 不满足 |
http://www.baidu.com:1234/test | 满足 | 满足 | 不满足 | 不满足 |
http://www.baidu.com:8888/test | 满足 | 满足 | 满足 | 不满足 |
http://www.baidu.com:8888/mypath | 满足 | 满足 | 满足 | 满足 |
从上表就可以清晰看出如何由data条件去限制Uri内容,从而得知一个Activity是否满足被启动的条件。
1.3 Data和Action的配对使用
在上一篇讲解Action的时候,提到了一个系统内置的,表示“做什么”的一个值:android.intent.action.VIEW。这个值和data共同使用,可以调用系统内置的应用,如浏览器、拨号、短信等。使用方法如下:
button.setOnClickListener(new OnClickListener(){
@Override
public void OnClick(View v){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});
button.setOnClickListener(new OnClickListener(){
@Override
public void OnClick(View v){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("tel://"));
startActivity(intent);
}
});
button.setOnClickListener(new OnClickListener(){
@Override
public void OnClick(View v){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("tel://123456"));
startActivity(intent);
}
});
这里由于打开的都是系统内置应用,因此并不需要在manifest文件中做修改,只需要传入Intent.ACTION_VIEW即可,Android就会知道你需要做某件事情的意愿。而具体做什么事情则由data决定,下面是较常使用的data格式:
http:// | 打开浏览器,后跟网址 |
tel:// | 打开拨号界面,后跟电话号码 |
smsto:// | 打开短信界面,后跟电话号码 |
我们也可以自己创建、设置能够响应打开浏览器、拨号界面等的Activity。新建Aty1,修改manifest文件中的设置如下:
<activity android:name=".Aty1"
android:label="Aty1">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
使用上面打开浏览器的代码不变。运行一次看看效果:
这次结果不再是直接打开系统内置浏览器,而是弹出了可以相应打开网页的Intent。其中除了内置浏览器外,也出现了我们自己新建的Aty1。创建能够响应用户拨号、短信操作的Activity方法是一样的,可以自己试一试。
2. Type
Type是对Data的类型作进一步的说明。Type在manifest中的设置同样也在<data>标签中,是data的mimeType属性。
mimeType包括许多文件类型,包括图片、视频、音频等等,每种类型下也可以包含多种文件格式,以下举例部分:
text/plain | 纯文本 |
image/gif | gif图像 |
image/jpeg | jpeg图像 |
video/mpeg | MPEG动画 |
audio/mp3 | mp3音乐 |
也可以不指定具体文件格式,只指定文件类型:
image/* | 指定类型为image的所有文件 |
audio/* | 指定类型为audio的所有文件 |
video/* | 指定类型为video的所有文件 |
我们可以通过setType获取指定格式的文件。在MainActivity中添加一个按钮,用于获取手机内指定格式文件。修改监听事件代码如下:
button.setOnClickListener(new OnClickListener(){
@Override
public void OnClick(View v){
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivity(intent);
}
});
运行程序,看看效果:
由于我使用的是模拟器,模拟器内部并没有图片,这四张图片是我临时使用camera存下来的图片。运行之后,我们成功地获取到了模拟器内的所有图片。
※ setData和setType不能同时使用。
有时候根据需求,我们会需要获取路径文件。也就是说,需要用setData通过Uri.parse("file://路径")去指定一个路径,同时也需要用setType去指定获取文件的类型。然而setData和setType是不可以同时使用的。当我们设置data的时候,系统会默认将type设置为null,当我们设置type的时候,系统会默认将data设置为null。也就是说,一般情况下,data和type我们只需要设置一个就行了,如果我们既想要设置data又想要设置type,那么可以使用:
Intent android.content.Intent.setDataAndType(Uri data, String type)
例如需要播放【指定路径】的【mp3文件】,我们就可以修改button的监听事件如下:
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri data = Uri.parse("file:///storage/sdcard0/刚好遇见你.mp3");
//设置data+type属性
intent.setDataAndType(data, "audio/mp3");
startActivity(intent);
}
});
运行后,Android就会按照指定路径去找到文件格式为MP3的音乐文件,并且开始播放。
由于Type属性值是在<data>标签中的mimetype,因此匹配规则和data一致,匹配时可以直接看作data的scheme、host、port、path等进行匹配。
3. Extra
这个就不多说了,在Activity之间传递数据用的尤其多。主要的使用方法就是:
intent.putExtra("键", "数据内容");
三、规定启动模式——Flag
Activity有四个启动模式,分别是standard、singleTop、singleTask和singleInstance。一般我们会在manifest中对某个Activity设定某种启动模式,但intent的flag属性同样可以为某个Activity设定启动模式。
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
//相当于singleTask
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
或者
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
//相当于singleTop
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
******************************************************************