从0开始认识android(四):Intent及intent-filtter详解

该系列的文章只是本人的一些个人理解、随笔、总结,也深怕误人子弟,如果理解有错的地方还希望看到的朋友指正,不胜感激!!!
  
  Intent(意图)可以用于启动Activity、Service和BroadcastReceiver组件,可以作为这三者间通信的信使。主要有显示意图和隐式意图两种:
  显示Intent:
  即启动一个组件时,指名道姓的启动,显示意图一般用于应用内(非跨应用)的组件通信,因为你的应用都有哪些组件,你肯定是清清楚楚的。
  
  隐式Intent:
  即启动一个组件时,不指名道姓,不将目标组件的类名传给Intent,那我们需要的组件怎么能够响应这个Intent?这就涉及到< intent-filter>了,虽然隐式意图我们没有传入目标组件类名,但需要我们为这个Intent传入目标组件在清单文件中定义的action(操作:说明这个界面能干什么,可以自定义)值、category(类别)值和data(数据:即这个组件完成功能需要的数据)值等。
  因此,只要我们一发射这个intent,那么所有在清单文件中定义了这些action值、category值的组件都可以响应这个intent被启动,不管是应用内的还是其他应用的。所以,隐式意图一般可用于跨应用的组件间通信。
  需要注意的是:不要用隐式intent启动service,也不要在清单文件中为service设置action、category等。因为service对用户是不可见的,万一我们本来就不想启动这个service,但隐式intent中的action、category等值又恰恰和我们这个service的相同,那么这个service也就于无形中被无意启动了。况且,从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用 bindService(),系统会引发异常。
  
  以下为常用的<intent-filter>标签:  
  action:
  一个意图过滤器至少要定义一个action,否则这个过滤器就是废的。一些常用的action系统已经定义好了,我们只需要直接用旧可以。
  android.intent.action.VIEW:从启动者的角度来说,假如你有一些图片或联系人数据,需要调用系统的图片查看器或拨号器来显示,那么你就需要调用setAction()为intent设置这个action。
  android.intent.action.SEND:还是从启动者的角度来说,如果你有数据需要通过其他应用共享出去,例如电子邮件应用或社交应用如qq、微信等,那你的intent就要设置这个action。
  自定义action:如果定义自己的操作,请确保将应用的包名作为前缀。
  
  category:
  android.intent.category.BROWSABLE:
  activity在清单文件中声明了这个category,则说明这个activity可以通过浏览器启动。反之,你要是启动这个activity,则启动的intent要调用addCategory()传入这个category。
  android.intent.category.LAUNCHER:
  这个category代表应用的启动界面,如果你有多个界面在清单文件中声明了这个category,那么你的应用在手机桌面就会有多个启动图标,如果这些界面没有指定自己的icon属性使用自己的界面图标的话,桌面的多个图标会清一色的显示的是你application节点中指定的icon图标,看起来就像一个应用重复装了多个.
  android.intent.category.DEFAULT:
  重点:如果你想让某个activity能够接受隐式intent,那么这个activity的意图过滤器必须声明这个category。
  
  data:
  这是重点哦~
  data顾名思义就是数据,主要由Uri和mimeType两大部分组成,你可以只定义Uri或者只定义mimeType,或者两者都定义:

<intent-filter . . . >
<data android:scheme="string"
      android:host="string"
      android:port="string"
      android:path="string"
      android:pathPattern="string"
      android:pathPrefix="string"
      android:mimeType="string" />
</intent-filter>

当然,这些组成部分你可以全部都定义在一个data中,也可以分别定义在多个data节点中:

<intent-filter . . . >
    <data android:scheme="something" />
    <data android:host="project.example.com" />
    . . .
</intent-filter>

上面的scheme、host、port、path、pathPrefix和pathPattern就是数据的Ur组成i:

<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]

uri的各个部分都有大小写之分,所以,最好都用小写来定义
1、如果你定义了[< path>|< pathPrefix>|< pathPattern>],那你必须要定义scheme和host;
2、如果你定义了port,那么你必须要定义scheme和host;
3、如果你定义了host,那么你必须要定义scheme。
当然,上面的1、2、3点你也可以不用定义scheme,但前提是你定义了mimeType。因为当你定义了mimeType确没定义scheme时,scheme协议默认是content:和file:
定义scheme:
直接写协议名称就可以了,不要带冒号或双斜杠。
定义host:
定义域名的时候,为了对相关的子域名也能响应,域名的第一部分我们可以用通配符 * 来代替,例如 * .google.com,那我们就能响应www.google.com,.google.com,developer.google.com等域名。
  而在代码中,你可以通过intent的setData()函数或setDataAndType()将你要带到目标组件中查看或分享的数据的Uri传给intent,setDataAndType()函数比setData()函数多传一个参数,这个参数是数据的MIME类型.
  需要注意的是:若要同时设置 URI 和 MIME 类型,请勿同时调用 setData() 和 setType(),因为它们会互相抵消彼此的值。请始终使用 setDataAndType() 同时设置 URI 和 MIME 类型。
  
  
  如果没有组件或应用响应我们的隐式Intent会怎样???
  出现这种情况,则调用将会失败,且应用会崩溃。要验证 Activity 是否会接收 Intent,请对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()。 如果结果为空,则不应使用该 Intent。如有可能,您应停用发出该 Intent 的功能。即:

Intent sendIntent = new Intent();
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

如果有多个应用响应我们的隐式Intent会怎样?
如果多个 Activity 可同时响应 Intent,则系统将显示一个对话框,让用户自己选择用哪个应用打开。
但如果用户勾选了”始终”用某个应用打开时,那么下次打开这类数据时就不会显示对话框了,而这次用户不想用之前的那个应用打开了,怎么办?
为了避免这种问题,我们需要每次显示的创建选择器:

Intent sendIntent = new Intent(Intent.ACTION_SEND);
... 
// 选择器标题,如“分享到” 
String title = getResources().getString(R.string.chooser_title);
// 创建选择器
Intent chooser = Intent.createChooser(sendIntent, title);
// 检测是否有应用能响应
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

APP有多个可以响应隐式intent的组件,但只能自己的APP启动,不想让其他应用启动,怎么办?
清单文件中将这些组件的exported 属性设置为 “false”即可。

猜你喜欢

转载自blog.csdn.net/jack_bear_csdn/article/details/80349830