作为一种系统级消息传递的机制,Intent有能力穿越进程边界传递结构化消息。
到目前为止,你已经了解了使用Intent来启动一个新的应用程序组件,但是,它们还可以通过sendBroadcast方法在组件间广播匿名消息。你可以在你的应用程序中实现Broadcast Receiver来监听和响应这些广播的Intent。广播Intent用于通知系统的监听者或应用程序事件,从而扩展了应用程序间的事件驱动编程模型。
广播Intent让你的程序更加开放;通过使用Intent来广播事件,你让你和第三方开发者响应事件而不需要修改你的原始程序。在你的应用程序里,你可以监听广播的Intent来替换或增强本地的(或第三方的)应用程序,或者对系统变化和应用程序事件作出响应。举个例子,通过监听外来的呼叫广播,你可以改变呼叫者的铃声或音量。
Android广泛地使用广播Intent来广播系统事件,如电池充电变化,网络连接和来电。
广播Intent是相当地简单。在你的程序组件里,构建你要广播的Intent,使用sendBroadcast方法发送出去。设定Intent的动作、数据和种类来使Broadcast Receiver精确地决定它们的兴趣。在这里,Intent动作字符串用来标识要广播的事件,因此,它必须是独一无二的标识事件的字符串。习惯的,动作字符串使用Java包的样子来定义,如下面的片段所示:
public static final String NEW_LIFEFORM_DETECTED = “com.paad.action.NEW_LIFEFORM”;
如果你想在Intent中包含数据,你可以使用Intent的data属性来指定一个URI。你还可以包含extras来增加额外的本地类型值。考虑就事件驱动模型而言,这些extras包等价于事件处理函数的可选参数。
下面的框架代码给出了一个广播的Intent的基本创建,使用之前定义的动作和一些以extras方法储存的额外的事件信息。
Intent intent = new Intent(NEW_LIFEFORM_DETECTED); intent.putExtra(“lifeformName”, lifeformType); intent.putExtra(“longitude”, currentLongitude); intent.putExtra(“latitude”, currentLatitude); sendBroadcast(intent);
Broadcast Receiver用于监听广播Intent。为了激活一个Broadcast Receiver,需要在代码或在程序manifest中注册。当注册一个Broadcast Receiver时,你必须使用Intent Filter来指定要监听哪个Intent。
为了创建一个新的Broadcast Receiver,需要扩展BroadcastReceiver类,并重写onReceive事件处理函数,如下面的框架代码所示:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //TODO: React to the Intent received. } }
当广播的Intent与注册的接收器的Intent Filter匹配时,onReceive方法会执行。onReceive处理函数必须在5秒内完成,否则应用程序无响应的对话框会显示。
在Intent广播的时候,注册有Broadcast Receiver的应用程序不需要正在运行。它们在有匹配的广播Intent时自动启动。这对于资源管理来说,是极好的,因为它允许你创建可以被关闭或杀死的事件驱动应用程序,而此刻又以安全的方式对广播事件做出响应。
典型的,Broadcast Receiver会更新内容、启动服务、更新Activity的UI或使用通知管理器来通知用户。5秒的执行限制确保了主进程不能,或者说不应该在Broadcast Receiver中直接结束。
下面的例子显示了如何实现一个Broadcast Receiver。
public class LifeformDetectedBroadcastReceiver extends BroadcastReceiver { public static final String BURN =“com.paad.alien.action.BURN_IT_WITH_FIRE”; @Override public void onReceive(Context context, Intent intent) { // Get the lifeform details from the intent. Uri data = intent.getData(); String type = intent.getStringExtra(“type”); double lat = intent.getDoubleExtra(“latitude”, 0); double lng = intent.getDoubleExtra(“longitude”, 0); Location loc = new Location(“gps”); loc.setLatitude(lat); loc.setLongitude(lng); if (type.equals(“alien”)) { Intent startIntent = new Intent(BURN, data); startIntent.putExtra(“latitude”, lat); startIntent.putExtra(“longitude”, lng); context.startActivity(startIntent); } } }
在程序的manifest中注册
为了在程序的manifest中包含一个Broadcast Receiver,通过在application节点增加一个receiver标签,并指定要注册的Broadcast Receiver的类名。receiver节点需要包含一个intent-filter标签来指定要监听的动作字符串,如下面的XML片段所示:
<receiver android:name=”.LifeformDetectedBroadcastReceiver”> <intent-filter> <action android:name=”com.paad.action.NEW_LIFEFORM”/> </intent-filter> </receiver>
Broadcast Receiver以这种方注册将总是处于活跃状态。
在代码中注册
你可以在代码中控制Broadcast Receiver的注册。这种做法的典型例子就是receiver用来在Activity中更新UI元素。一个好的习惯是当Activity不可见(或不活跃)时,反注册Broadcast Receiver。
下面的代码片段显示了如何使用一个Intent Filter注册Broadcast Receiver:
// Create and register the broadcast receiver. IntentFilter filter = new IntentFilter(NEW_LIFEFORM_DETECTED); LifeformDetectedBroadcastReceiver r = new LifeformDetectedBroadcastReceiver(); registerReceiver(r, filter);
unregisterReceiver(r);
Android给许多系统服务广播Intent。你可以使用这些基于系统事件的消息来给自己的工程增添一些功能,这些事件如时区变更、数据连接状态、SMS消息或电话呼叫。
下面的列表介绍了一些Intent类中的本地动作常量;这些动作基本上用于设备状态改变的跟踪:
❑ ACTION_BOOT_COMPLETED
一旦设备完成启动时触发。需要RECEIVE_BOOT_COMPLETED权限。
❑ ACTION_CAMERA_BUTTON
摄像头按被按下时触发。
❑ ACTION_DATE_CHANGED和ACTION_TIME_CHANGED
当手动修改日期或时间时广播这两个动作。
❑ ACTION_GTALK_SERVICE_CONNECTED和ACTION_GTALK_SERVICE_DISCONNECTED
当GTalk连接或丢失连接时广播这两个动作。更多GTalk消息将在第9章详细讨论。
❑ ACTION_MEDIA_BUTTON
媒体按钮按下时触发。
❑ ACTION_MEDIA_EJECT
当用户选择弹出外部的储存媒体,会首先触发这个。如果你的程序读写到外部媒体存储器,你应该监听这个事件来保存和关闭任何打开的文件句柄。
❑ ACTION_MEDIA_MOUNTED和ACTION_MEDIA_UNMOUNTED
当新的外部存储媒体成功地添加到设备或从设备移除时触发。
❑ ACTION_SCREEN_OFF和ACTION_SCREEN_ON
当屏幕打开或关闭时广播。
❑ ACTION_TIMEZONE_CHANGED
当电话的当前时区变更时会广播这个动作。Intent中包含一个ID为java.util.TimeZone的时区extras。
Android用来通知应用程序状态变更的动作的列表可参考:
http://code.google.com/android/reference/android/content/Intent.html.
Android还使用Broadcast Receiver来监听特定的事件如SMS消息接收。动作和与这些事件关联的Intent将在后面的章节详细讨论,等你了解了更多关于关联服务之后。