与其他APP通信(3)-- 允许其他应用启动你的Activity
前两课关注了故事的一方:从你的应用中启动另一个应用的activity。但是如果你的应用可以执行一些对其他应用可能有用的动作,那么你应该准备好响应从其它应用发送过来的动作请求。例如,你创建一个社交应用,可以与用户的朋友分享消息或者图片,那么你应该有兴趣支持ACTION_SEND Intent,这样用户可以从其他应用初始化一个“分享”动作,然后启动你的应用执行这个动作。
为了允许其他应用启动你的activity,你需要在你的配置文件里为对应的<activity>元素添加一个<intent-filter>元素。
当你的应用安装到手机上的时候,系统会识别你的Intent过滤器,添加信息到所有已经安装应用支持的intent的内部目录表里。当一个应用使用一个隐式intent调用startActivity()或者startActivityForResult()时,系统会找出哪个activity(或哪些activity)可以响应这个intent。
添加一个Intent过滤器
为了合理地声明你的activity能够处理的intent,根据动作类型和activity可以接受的数据类型,每一个添加的intent过滤器应该越细致越好。
如果一个activity有一个intent过滤器满足下面的Intent标准,那么系统可能会将一个给定的Intent发送给这个activity:
Action
一个字符串,命名了动作的名字。通常会是平台定义的值如ACTION_SEND或者ACTION_VIEW。
在你的intent过滤器中使用<action>元素指定。这个指定的值必须是一个完全的字符串名字而不是一个API常量(查看下面的例子)
Data
描述了与这个intent绑定的数据。
在你的intent过滤器中使用<data>元素指定。你可以使用这个元素中的一个或者多个属性,只指定MIME类型,或只指定URI前缀,或只指定URI协议框架,或者这些和其他的组合来指定可以接受的数据类型。
注意:如果你不需要声明数据Uri的细节的话(例如你的activity处理其他各类的”额外”数据,而不是URI),那么 你可以只是使用android:mimeType属性来指定你的activity可以处理的数据类型,比如text/plain或image/jpeg。
Category
提供一个附加的方法来加强处理某个intent的activity的特征,通常与用户手势或被启动的位置相关。有几个被系统支持的域,但是大多数都很少使用。虽然如此,所有隐式的intent默认属于CATEGORY_DEFAULT域。
在你的intent过滤器中使用<category>元素。
在你的intent过滤器中,你可以在<intent-filter>元素中针对每一个标准嵌入相关的XML元素,来声明你的activity可以接受的intent。
例如,这里有一个activity,它有一个intent过滤器可以处理ACTION_SEND Intent,并且要求数据要么是文本类型的,要么是一个图像:
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>
每一个发送过来的Intent都只能指定一个动作和一个数据类型,但是允许在同一个<intent-filter>中指定多个<action>,<category>和<data>。
如果两对动作和数据同时互斥,那么你应该创建单独的intent过滤器来指定当配对的数据类型满足的情况下,这个动作才是可接受的。
例如,假如你的activity对于ACTION_SEND和ACTION_SENDTO的动作可以同时处理文本和图像。在这种情况下,你必须为这两个动作定义两个单独的intent过滤器,因为ACTION_SENDTO intent必须基于URI协议send或sendto来使用一个Uri数据来指定接收者的地址。例如:
<activity android:name="ShareActivity">
<!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
<intent-filter>
<action android:name="android.intent.action.SENDTO"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="sms" />
<data android:scheme="smsto" />
</intent-filter>
<!-- filter for sending text or images; accepts SEND action and text or image data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
注意:为了接收隐式的intent,你必须在intent过滤器中包含CATEGORY_DEFAULT域。方法startActivity()和startActivityForResult()认为所有的intent都包含在CATEGORY_DEFAULT域中。如果你不声明它,那么你的activity将接收不到任何隐式的intent。
在你的Activity中处理Intent
为了决定在你的activity中执行什么动作,你可以读取启动你的activity的intent。
在你的activity启动的时候,调用getIntent()方法检索启动intent。你可以在你的activity的生命周期期间任何时候调用,但是通常情况下,你应该在早期阶段的回调例如onCreate()或onStart()中调用。
例如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the intent that started this activity
Intent intent = getIntent();
Uri data = intent.getData();
// Figure out what to do based on the intent type
if (intent.getType().indexOf("image/") != -1) {
// Handle intents with image data ...
} else if (intent.getType().equals("text/plain")) {
// Handle intents with text ...
}
}
返回一个结果
如果你想给启动你的activity的那个源activity返回一个结果,你可以调用setResult()来指定结果代码和结果Intent。当你的操作结束,并且用户应该返回到源activity,那么需要调用finish()来关闭你的Activity。例如:
// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();
你必须总是为结果指定结果代码。通常地,值应该是RESULT_OK或RESULT_CANCELED。然后如果需要的话,你可以为Intent提供额外的数据。
注意:默认情况下结果被设置为RESULT_CANCELED。如果用户在完成动作前和在你设置结果前点击了后退按钮,那么源activity就会收到”canceled”结果。
如果你需要简单地返回一个整型数字来表明几个结果中的某种情况时,你可以将结果代码设置为一个大于0的数。如果你使用结果代码来传递一个整数,并且你不需要包含一个Intent,那么你可以调用setResult(),并且只传递一个结果代码,例如:
setResult(RESULT_COLOR_RED);
finish();
在这种情况下,可能存在多种结果,所以这个结果代码是本地定义的整数(大于0)。当你把结果返回给你自己的应用时,这样可以工作地很好,因为接收到结果代码的activity可以通过查询全局公共常量来决定结果代码的实际意义。
注意:没有必要检查你的activity的启动是通过调用startActivity()还是startActivityForResult()。你可以简单地调用setResult(),如果你认为启动你的Activity的intent可能需要一个返回结果。如果源activity确实调用了startActivityForResult(),那么系统会把你的setResult()中的结果返回给它,否则,就简单地忽略结果。