使用Intent Filter实现插件和扩展
到目前为止,你已经学会了如何显式地创建隐式Intent,但这只是故事的一半。Android允许后来的包为已有的应用程序提供新的功能,在运行时使用Intent Filter动态地填入菜单。
这为你的Activity提供了插件模型,使它们可以利用目前还未构想到的新应用程序组件的功能性,而不需要修改或重新编译你的工程。
Menu类的addIntentOptions方法允许你指定一个Intent,它描述了这个Menu要作用的数据。Android解析这个Intent并返回每个在Intent Filter中匹配特定的数据的指定动作。为每一个创建一个新的菜单项,用匹配的Intent Filter的标签来填入文本。
这个概念的优雅之处可以通过例子很好的解释清楚。话说你的应用程序显示的数据是地点的列表。跳到几年前的某一个时刻,菜单动作可能包括“查看”和“显示去的方向”,现在你创建了一个应用程序与汽车交互,允许你的电话来处理驾驶。感谢运行时的菜单生成,通过在新的Activity节点里包含一个新的Intent Filter(里面有一个DRIVE_CAR动作),Android会自动地在你的老应用程序里为这个动作添加一个新的菜单项。
当你创建了一个能在特定类型数据上执行动作的新组件时,运行时菜单填入机制让程序的功能具有了翻新的能力。许多Android本身的应用程序使用这个功能,让你可以在本地的Activity中增添额外的动作。
为应用程序提供匿名动作
为了让其它应用程序获得这些动作,通过在它们的manifest节点里添加intent-filter标签来发布它们。
Intent Filter描述了它能执行的动作以及可以执行的数据。后者在Intent解析过程中决定什么时候这个动作有效的期间使用。种类的标签必须是ALTERNATIVE和SELECTED_ALTERNATIVE之一或两者。菜单项使用的文本在android:label属性中指定。
下面的XML显示了使用Intent Filter来发布一个Activity有从轨道上秒杀月球的能力。
<activity android:name=”.NostromoController”>
<intent-filter android:label=”Nuke From Orbit”>
<action android:name=”com.pad.nostromo.NUKE_FROM_ORBIT”/>
<data android:mimeType=”vnd.moonbase.cursor.item/*”/>
<category android:name=”android.intent.category.ALTERNATIVE”/>
<category android:name=”android.intent.category.SELECTED_ALTERNATIVE”/>
</intent-filter>
</activity>
Content Provider和用来运行这个例子的其它代码没有提供;接下来的章节里,你将会看到如何书写代码来让这个动作在其它的Activity的菜单中可用。
在你的Activity菜单中并入匿名动作
在运行时为你的菜单添加选项,你可以考虑在菜单对象上使用addIntentOptions方法,传入一个Intent,指定了你想提供的动作所需的数据。一般来说,它会被Activity的onCreateOptionsMenu和onCreateContextMenu处理函数处理。
你创建的Intent将用于解析在Intent Filter中提供了能在你指定数据上执行动作的组件。Intent用于查找动作,所以不要指定一个;它只需要指定指定动作所需的数据。你也必须制定动作的种类为CATEGORY_ALTERNATIVE或CATEGORY_SELECTED_ALTERNATIVE。
下面的框架代码显示了为菜单-动作解析创建一个Intent:
Intent intent = new Intent();
intent.setData(MyProvider.CONTENT_URI);
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
在你想要填入的菜单里传递这个Intent到addIntentOptions方法中,还包括任一选项标志,调用类的名称,菜单的组和菜单的ID值。你还可以指定一个Intent数据来创建附加的菜单项。
接下来的代码片段给出了如何动态填入Activity菜单的想法,它可能包含前一章节提到的“月球秒杀”的动作:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Create the intent used to resolve which actions
// should appear in the menu.
Intent intent = new Intent();
intent.setData(MoonBaseProvider.CONTENT_URI);
intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE);
// Normal menu options to let you set a group and ID
// values for the menu items you’re adding.
int menuGroup = 0;
int menuItemId = 0;
int menuItemOrder = Menu.NONE;
// Provide the name of the component that’s calling
// the action -- generally the current Activity.
ComponentName caller = getComponentName();
// Define intents that should be added first.
Intent[] specificIntents = null;
// The menu items created from the previous Intents
// will populate this array.
MenuItem[] outSpecificItems = null;
// Set any optional flags.
int flags = Menu.FLAG_APPEND_TO_GROUP;
// Populate the menu
menu.addIntentOptions(menuGroup, menuItemId, menuItemOrder,
caller, specificIntents, intent, flags, outSpecificItems);
return true;
}