Intent filter 关于Action、Category属性详解
说几句俗话:
对应Activity,Service等四大组件在AndroidManifest.xml中设置Action的值,相当于对外,包括对其他app暴露自己是可以被外面调用,为其他组件(或者app)服务的,其他组件(或app)使用:
Intent intent=new Intent();
intent.setAction(Action字符窜[intent.name]);
startActivity(intent);
其中Category约束条件为DEFAULT,只要其他匹配IntentFilter中的action相符,即通过检查,被暴露的组件或者APP机会启动并进行为启动者提供服务.
如果加了Category约束条件:那么启动者还要在启动intent之前提供Category相同的证明条件,可以是多个,只要其中一个相符,被暴露的组件或者APP将会启动并进行为启动者提供服务.
最后给出了自己的例子.
如果一个 Intent 请求在一片数据上执行一个动作, Android 如何知道哪个应用程序(和组件)能用来响应这个请求呢? Intent Filter就是 用来注册 Activity 、 Service 和 Broadcast Receiver 具有能在某种数据上执行一个动作的能力。使用 Intent Filter ,应用程序组件告诉 Android ,它们能为其它程序的组件的动作请求提供服务,包括同一个程序的组件、本地的或第三方的应用程序。
为了注册一个应用程序组件为 Intent 处理者,在组件的 manifest 节点添加一个 intent-filter 标签。在 Intent Filter 节点里使用下面的标签(关联属性),你能指定组件支持的动作、种类和数据。
1、动作测试:
<activity android:name="com.x210.intentfilters.OneActivity" android:label="oneActivity"> <intent-filter> <action android:name="myapp.action.test1" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
规则a.一条<intent-filter>元素至少应该包含一个<action>,否则任何Intent请求都不能和该<intent-filter>匹配。
<activity android:name="com.x210.intentfilters.OtherActivity" android:label="otherActivity"> <intent-filter> <category android:name="cate1"/> <category android:name="cate2"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
以上<intent-filter>元素没有包含<action>标签,任何Intent请求都无法与该<intent-filter>匹配。
规则b.如果Intent请求的Action和<intent-filter>中个某一条<action>匹配,那么该Intent就通过了这条<intent-filter>的动作测试。
<activity android:name="com.x210.intentfilters.OneActivity" android:label="oneActivity"> <intent-filter> <action android:name="myapp.action.test1" /> <action android:name="myapp.action.test2" /> <action android:name="myapp.action.test3" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
以下几种Intent请求都可以通过上述<intent-filter>的动作测试。
请求1:
Intent intent = new Intent("myapp.action.test1"); startActivity(intent);
请求2:
Intent intent = new Intent("myapp.action.test2"); startActivity(intent);
如果Intent请求或<intent-filter>中没有说明具体的Action类型,那么会出现下面两种情况。
(1) 如果<intent-filter>中没有包含任何Action类型,那么无论什么Intent请求都无法和这条<intent-filter>匹配;
(2) 反之,如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。
2、类别测试
<activity android:name="com.x210.intentfilters.OtherActivity" android:label="otherActivity"> <intent-filter> <action android:name="myapp.action.test1" /> <category android:name="cate1"/> <category android:name="cate2"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
只有当Intent请求中所有的Category与组件中某一个IntentFilter的<category>完全匹配时,才会让该 Intent请求通过测试,IntentFilter中多余的<category>声明并不会导致匹配失败。一个没有指定任何类别测试的 IntentFilter仅仅只会匹配没有设置类别的Intent请求。
以下三种Intent请求都可以通过上述<intent-filter>的类别测试。
请求1:
Intent intent = new Intent("myapp.action.test1"); intent.addCategory("cate1"); startActivity(intent);
请求2:
Intent intent = new Intent("myapp.action.test1"); intent.addCategory("cate2"); startActivity(intent);
请求3:
Intent intent = new Intent("myapp.action.test1"); intent.addCategory("cate1"); intent.addCategory("cate2"); startActivity(intent);
下面是我做的demo,需要两个工程:
工程一:
java :
package com.example.calledactdemo; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button mStartBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mStartBtn=(Button)findViewById(R.id.button2); mStartBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { // TODO Auto-generated method stub Intent i=new Intent("android.intent.action.TESTING"); i.addCategory("test"); // i.setClassName("com.example.callingactdemo", "com.example.callingactdemo.MainActivity"); MainActivity.this.startActivity(i); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
xml :
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.calledactdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.calledactdemo.MainActivity" android:exported="true" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.TESTED"></action> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
工程二:
java :
package com.example.callingactdemo; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button mStartBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mStartBtn=(Button)findViewById(R.id.button2); mStartBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { // TODO Auto-generated method stub Intent i=new Intent("android.intent.action.TESTED"); i.addCategory("android.intent.category.DEFAULT"); // i.setAction("android.intent.action.TESTED"); // i.setClassName("com.example.calledactdemo", "com.example.calledactdemo.MainActivity"); MainActivity.this.startActivity(i); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
xml :
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.callingactdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.callingactdemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.TESTING"></action> <category android:name="test" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
上面是设置各种各样限定条件,相当于有偿服务.
如果直接通过引用包名,就会无视上面的条件:
工程一修改如下:
Intent i=new Intent(); i.setClassName("com.example.callingactdemo", "com.example.callingactdemo.MainActivity"); MainActivity.this.startActivity(i);
工程二修改如下:
Intent i=new Intent(); i.setClassName("com.example.calledactdemo", "com.example.calledactdemo.MainActivity"); MainActivity.this.startActivity(i);
其他不变,同样可以互相启动.