说明:Intent是“意图”的意思,Intent通过指明当前组件想要执行的动作,让系统知道我们的“意图”之后,完成的一系列操作,除此之外,Intent还可以在不同组件之间传递数据。Intent一般可被用于启动活动
(Activity(startActivity(intent)))
、启动服务(Service(startService(intent)))
以及发送广播(Broadcast(sendBroadcast(intent)))
等场景,本篇笔记主要记载Intent启动活动的知识。
Intent大致可以分为两种:显式Intent和隐式Intent。
①ComponentName(组件):目的组件
②Action(动作):用来表现意图的行动
③Category(类别):用来表现动作的类别
④Data(数据):表示与动作要操纵的数据
⑤Type(数据类型):对于data范例的描写
⑥Extra(扩展信息):扩展信息
⑦Flags(标志位):期望这个意图的运行模式
按照分类可以分为以下三种:
1.用于启动:ComponetName(显式)、Action(隐式)、Category(隐式)。
2.用于传递数据:Data(隐式)、Type(隐式)、Extra(显式、隐式)。
3.用于规定启动模式:Flags.
有关七大属性讲解详见《Intent七大属性》
Intent有多个构造函数的重载,其中一个是:
Intent(Context packageContext,Class> cls)
第一个参数Context要求提供一个启动活动的上下文;
第二个参数Class指定想要启动的活动目标.
通过这个构造函数就可以构建出Intent的“意图”,最后调用startActivity()方法就可以启动目标活动了。
在MainActivity中重写onClick()方法:
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.start_aty2:
Intent intent = new Intent(MainActivity.this,Aty2.class);
startActivity(intent);
}
}
或者:
@Override
public void onClick(View view) {
Intent intent = new Intent();
switch (view.getId()){
case R.id.start_aty2:
intent.setClass(MainActivity.this,Aty2.class);
//或者调用setComponent方法说明“意图”,启动活动
//intent.setComponent(new ComponentName(MainActivity.this,Aty2.class));
startActivity(intent);
}
}
通过查看源码,可以发现ComponentName还有其他三种构造函数的重载
所以我们也可以通过包名来说明“意图”,启动其他活动。
有关用法可以参考:《[Android基础]Intent用法的二三事(上)》
隐式Intent并不明确指出我们想要启动哪一个活动,而是通过指定一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
通过隐式配置的Activity可以跨应用被启动。
如果不想被别的应用启动,可以在activity配置中加上:android:exported="false"
(默认为true)
(1)首先我们需要给aty3配置intent-filter,指定当前活动能够响应的action和category,打开AndroidManifest.xml,添加如下代码:
配置action名字的规则通常为:包名.intent.action.类名字
(2)在MainActivity的onClick()方法中:
case R.id.start_aty3:
intent.setAction("com.example.aboutintent.intent.action");
startActivity(intent);
或者:
case R.id.start_aty3:
Intent intent = new Intent("com.example.aboutintent.intent.action");
startActivity(intent);
这是最简单的隐式Intent,指明action且该action名字只属于该Activity,即可启动活动。
action的匹配规则:
(1)对于设置了action的Activity来说,如果要隐式启动该Activity,就必须匹配到它的action
(2)每个Activity可以设置多个action,但是匹配的时候只能匹配其中一种。
系统也有一些自带的action属性值供我们参考:
属性值 | 作用 |
---|---|
ACTION_MAIN | 程序入口,每个APP必须至少有一个Activity包含一个此类型的Action说明。 |
ACTION_DIAL | 打开系统默认的拨号程序,如果Data中设置了电话号码,则自动在拨号程序中输入此号码。 |
ACTION_CALL | 直接拨打Data设置好的号码 |
ACTION_VIEW | 根据不同的Data类型,显示不同的数据 |
ACTION_SEND | 由用户指定发送方式进行数据发送操作 |
当两个activity配置的action是一样的时候,那么系统会启动哪个活动呢?
(1)配置intent-filter
(2)在MainActivity中不变
因此,不同的Activity配置同一个action值时,使用Intent通过action去启动Activity时,Android通过过滤器对action进行匹配筛选,就会得到多个Activity。
前面我们已经说过通过隐式Intent我们可以跨应用启动活动。
(1)首先我们在同一个项目中新建一个module——app1
(2)在app1的入口活动中添加按钮控件,并加入响应事件:
findViewById(R.id.app1_start_aty3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.aboutintent.intent.action");
startActivity(intent);
}
});
(4)假如我们给aty3配置:android:exported="false"
,即
再次运行app1并启动aty3会发生什么呢?
效果图:
会发生报错,我们看一下打印日志:
可以看出app1没有aty3的访问权。
当然我们可以通过try{}catch{}解决这个问题:
findViewById(R.id.app1_start_aty3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
Intent intent = new Intent("com.example.aboutintent.intent.action");
startActivity(intent);
}catch (Exception e){
Toast.makeText(MainActivity.this,"没有访问权限",Toast.LENGTH_SHORT).show();
}
}
});
效果图:
(当然,这只是我这个小菜鸡的菜鸡解决方法,如果还有其他解决方法,也可以交流一哈)
category的匹配规则:
category也是一个用户自定义的字符串,但和action不一样的是,它可以在intent中通过intent.addCategory设置多个category的值。
(1)假设我们给aty3配置多一个category:
(2)然后在MainActivity中的onCreat()方法加上:
那么还会不会出现上面展示两种活动让你选择的情况呢?
明显是不会了。
因此,在匹配时,通过过滤器寻找到的Activity必须包含intent设置的所有category的值。
注意:CATEGORY_DEFAULT是隐式启动一个Activity必不可少的一个属性值。使用隐式启动Activity,我们都应该主动加上CATEGORY_DEFAULT这个属性值。(app入口Activity除外)
我们知道,使用隐式Intent还可以启动其他程序的活动,除了上面我们自己创建的app1,还可以启动百度、系统自带的拨号程序什么的,这可以实现Android多个应用程序的功能共享。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器,而是只需要调用系统自带的浏览器来打开这个网页就可以了。
(1)启动百度:
case R.id.start_baidu:
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
break;
这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,讲一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。
效果图:
(2)启动拨号面板:
case R.id.start_dial:
intent.setAction(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
break;
我们给aty3配置data属性并加上
,再次点击隐式启动百度按钮,看看会发生什么?
可以看出系统自动弹出了一个列表,显示了目前能够响应这个Intent的所有程序。因为我们在标签中通过android:scheme指定了数据的协议必须是http协议,这样Aty3就和浏览器一样。能够响应一个打开网页的Intent了。
需要注意的是:虽然我们声明了Aty3是可以响应打开网页的Intent,但实际上这个活动并没有加载并显示网页的功能,所以真正的项目中尽量不要出现这种有可能误导用户的行为,不然用户体验极差。
参考来自:http://blog.csdn.net/tahlia_/article/details/78020003
http://blog.csdn.net/iblade/article/details/50478701