[Android基础]Intent用法的二三事(下)——Data、Type、Extra、Flag的属性详解

来源:互联网 发布:手机淘宝自动挂机赚钱 编辑:程序博客网 时间:2024/05/29 10:34

上一篇详细讲解了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:httpscheme:http
host:www.baidu.comscheme:http
host:www.baidu.com
port:8888scheme:http
host:www.baidu.com
port:8888
path:/mypathhttp: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/gifgif图像image/jpegjpeg图像video/mpegMPEG动画audio/mp3mp3音乐

也可以不指定具体文件格式,只指定文件类型:

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);    }});


其中Intent.ACTION_GET_CONTENT是系统内置的动作,它允许用户选择特殊种类的数据。这里我们使用setType指定了打开的文件类型为图片,图片格式不限。换句话说,就是获取所有图片了。

运行程序,看看效果:


由于我使用的是模拟器,模拟器内部并没有图片,这四张图片是我临时使用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(){@Overridepublic 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);//相当于singleTaskintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);
或者

Intent intent = new Intent(MainActivity.this,SecondActivity.class);//相当于singleTopintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);startActivity(intent);


******************************************************************