zoukankan      html  css  js  c++  java
  • 接收广播BroadcastReceiver

    Broadcast Receiver用于接收并处理广播通知(broadcast announcements)。多数的广播是系统发起的,如地域变换、电量不足、来电来信等。程序也可以播放一个广播。程序可以有任意数量的 broadcast receivers来响应它觉得重要的通知。broadcast receiver可以通过多种方式通知用户:启动activity、使用NotificationManager、开启背景灯、振动设备、播放声音等,最 典型的是在状态栏显示一个图标,这样用户就可以点它打开看通知内容。
    通常我们的某个应用或系统本身在某些事件(电池电量不足、来电来短信)来临时会广播一个Intent出去,我们可以利用注册一个Broadcast Receiver来监听到这些Intent并获取Intent中的数据。


    一个Broadcast receiver只有一个简单的回调函数:

    onReceive(Context curContext, Intent broadcastMsg),当一个广播消息被Receiver监听到时,Android会调用它的onReceive()方法,并将包含消息的 Intent对象传给它。 onReceive中代码的执行时间不要超过5s,否则android会弹出超时dialog。 此时是否另开一个线程来处理耗时的操作呢?
    Receiver只在onReceive方法执行时是激活状态,只要onReceive一返回,Receiver就不再是激活状态了。Receiver进 程是被一个激活状态的broadcast receiver所保护而不被系统终止的,一旦onReceive返回,Receiver进程broadcast receiver所保护而变为一个空进程,空进程是可以在任意时刻被终止的。这就带来了一个问题:当响应一个广播信息的处理十分耗时的时候,那么就应该把 这个处理放在一个单独的线程里去执行,来保证主线程里的其他用户交互组件能够继续运行,而一旦这么做,当onReceive()唤起一个线程后就会马上返 回,这时就会把Receiver进程放到被终止的境地。解决这个问题的方案是在onReceive()里开始一个Service,让这个Service去 做这件事情,那么系统就会认为这个进程里还有活动正在进行。

    我们看一个简单的demo,该demo实现了一个自定义broadcast。

    发送端这个activity中创建了一个按钮,当按钮被按下的时候通过sendBroadcast()发送一个broadcast。
     
    Java代码  收藏代码
    1. public class BroadcastTest extends Activity {     
    2.     public static final String NEW_LIFEFROM_DETECTED = “com.android.broadcasttest.NEW_LIFEFROM”;    
    3.   
    4.         public void onCreate(Bundle savedInstanceState) {     
    5.             Button btn0 = (Button)findViewById(R.id.btn0);     
    6.             btn0.setOnClickListener(new OnClickListener() {     
    7.                 public void onClick(View v) {     
    8.                         Intent it = new Intent(NEW_LIFEFROM_DETECTED);    
    9.                         sendBroadcast(it);     
    10.                 }     
    11.             });     
    12.         }     
    13.     }    
     接收端在onReceive()中实现了当接收到broadcast所做的动作。
    Java代码  收藏代码
    1. Public class MyBroadcastReceiver extends BroadcastReceiver {    
    2.     // TODO    
    3.     Public void onReceive(Context context, Intene intent){     
    4.          ......    
    5.      }     
    6. }    
     在receiver的action中定义了该receiver能够接受的广播,Manifest.xml定义部分:
    Java代码  收藏代码
    1. <receiver android:name=”.MyBroadcastReceiver”>   
    2.    <intent-filter>   
    3.          <action android:name=”com.android.broadcasttest.NEW_LIFEFROM” />    </intent-filter>  
    4.  </receiver>    
     
    Broadcast机制是基于一种注册方式的,Broadcast Receiver将其特征描述并注册在系统中。根据注册时机,可以分为两类,网上有人称之为冷注册和热注册。
           冷注册,就是Broadcast Receiver的相关信息写在配置文件中,系统会负责在相关事件发生的时候及时通知到该Broadcast Receiver。这种模式适合于这样的场景:某事件发生 -> 通知Broadcast -> 启动相关处理应用。比如,监听来电、邮件、短信之类的,都隶属于这种模式。
     
           热注册,顾名思义,注册这样的事情都是由应用自己来处理的,通常是在OnResume事件中通过registerReceiver进行注册,在 OnPause等事件中通过unregisterReceiver反注册,通过这种方式使其能够在运行期间保持对相关事件的关注。比如,一款优秀的词典软 件,可能会有在运行期间关注网络状况变化的需求,使其可以在有廉价网络的时候优先使用网络查询词汇,在其他情况下,首先通过本地词库来查词。而这样的监 听,只需要在其工作状态下保持就好,不运行的时候,管你是天大的网路变化,与我何干。其模式可以归结为:启动应用 -> 监听事件 -> 发生时进行处理。
     
    总结:注册的方式由静态注册和动态注册两种。对于有序消息,动态注册的BroadcastReceiver总是先于静态注 册的BroadcastReceiver被触发。对于同样是动态注册的BroadcastReceiver,优先级别高的将先被触发,而静态注册的 BroadcastReceiver总是按照静态注册的顺序执行。
     
    在AndroidManifest.xml中注册
    Java代码  收藏代码
    1. <receiver android:name="Receiver1">  
    2.         <intent-filter>  
    3.                <!-- 和Intent中的action对应 -->  
    4.                 <action android:name="com.forrest.action.mybroadcast"/>  
    5.         </intent-filter>  
     在代码中注册
    Java代码  收藏代码
    1. IntentFilter filter = new IntentFilter("com.forrest.action.mybroadcast"); // 和广播中Intent的action对应  
    2. MyBroadcastReceiver br = new MyBroadcastReceiver();  
    3. registerReceiver(new MyBroadcastReceiver(), filter);  
    4.   
    5. //注销  
    6. unregisterReceiver(br);  
     
    Example1:
    Java代码  收藏代码
    1. public class Receiver1 extends BroadcastReceiver {  
    2.         private Context context;  
    3.         public static final int NOTIFICATION_ID = 10001;  
    4.           
    5.         public void onReceive(Context context, Intent intent) {  
    6.                 this.context = context;  
    7.                 showNotification();  
    8.         }  
    9.           
    10.         private void showNotification() {  
    11.                 Notification notification = new Notification(R.drawable.icon, "来电话啦...", System.currentTimeMillis());  
    12.                 PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);  
    13.                 notification.setLatestEventInfo(context, "来电话啦...嘿嘿", "赶紧接电话,否则误大事了", contentIntent);  
    14.                   
    15.                 NotificationManager notificationManager = (NotificationManager) context.getSystemService(  
    16.                                 android.content.Context.NOTIFICATION_SERVICE);  
    17.                 notificationManager.notify(NOTIFICATION_ID, notification);  
    18.         }  
    19. }  
     
    Java代码  收藏代码
    1. public class Receiver2 extends BroadcastReceiver {  
    2.         private Context context;  
    3.           
    4.         @Override  
    5.         public void onReceive(Context context, Intent intent) {  
    6.                 this.context = context;  
    7.                 deleteNotification();  
    8.         }  
    9.           
    10.         private void deleteNotification() {  
    11.                 NotificationManager notificationManager = (NotificationManager) context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);  
    12.                 notificationManager.cancel(Receiver1.NOTIFICATION_ID);  
    13.         }  
    14. }  
     
    Java代码  收藏代码
    1. public class MainActivity extends Activity {  
    2.         private final String ACTION_SEND = "com.forrest.action.SENDMESSAGE",  
    3.                                                  ACTION_CLEAR = "com.forrest.action.CLEARNOTIFICATION";  
    4.           
    5.     public void onCreate(Bundle savedInstanceState) {  
    6.         super.onCreate(savedInstanceState);  
    7.         setContentView(R.layout.main);  
    8.         ( (Button) findViewById(R.id.btn1) ).setOnClickListener(new OnClickListener() {  
    9.                 public void onClick(View v) {  
    10.                         clickMenuItem(ACTION_SEND);  
    11.                 }  
    12.         });  
    13.         ( (Button) findViewById(R.id.btn2) ).setOnClickListener(new OnClickListener() {  
    14.                 public void onClick(View v) {  
    15.                         clickMenuItem(ACTION_CLEAR);  
    16.                 }  
    17.         });  
    18.     }  
    19.       
    20.     private void clickMenuItem(final String action) {  
    21.             Intent intent = new Intent(action);  
    22.             sendBroadcast(intent);  
    23.     }  
    24. }  
     
    Java代码  收藏代码
    1. <application android:icon="@drawable/icon" android:label="@string/app_name">  
    2.     <activity android:name=".MainActivity"  
    3.               android:label="@string/app_name">  
    4.         <intent-filter>  
    5.             <action android:name="android.intent.action.MAIN" />  
    6.             <category android:name="android.intent.category.LAUNCHER" />  
    7.         </intent-filter>  
    8.     </activity>  
    9.     <receiver android:name="Receiver1">  
    10.             <intent-filter>  
    11.                     <action android:name="com.forrest.action.SENDMESSAGE"/>  
    12.             </intent-filter>  
    13.     </receiver>  
    14.     <receiver android:name="Receiver2">  
    15.             <intent-filter>  
    16.                     <action android:name="com.forrest.action.CLEARNOTIFICATION"/>  
    17.             </intent-filter>  
    18.     </receiver>  
    19. </application>  
    Example2:
    当设备接收到一条新的SMS消息时,就会广播一个包含了 android.provider.Telephony.SMS_RECEIVED动作的Intent。注意,这个动作是一个字符串值,SDK 1.0不再包含对这个字符串的引用,因此,在你的应用程序中,你需要显式的指定它。

    对于应用程序监听SMS Intent广播,首先需要添加RECEIVE_SMS权限。通过在应用程序manifest中添加一个uses-permission,如下面的片段所示:

    <uses-permission android:name=”android.permission.RECEIVE_SMS”/>

    SMS广播Intent包含了新来SMS的细节。为了提取包装在SMS广播Intent的Bundle中的SmsMessage对象数组,使用pdus key来提取SMS pdus数组,其中,每个对象表示一个SMS消息。将每个pdu字节数组转化成SmsMessage对象,调用 SmsMessage.createFromPdu,传入每个字节数组,如下面的片段所示:
    Java代码  收藏代码
    1. Bundle bundle = intent.getExtras();  
    2.     if (bundle != null) {  
    3.         Object[] pdus = (Object[]) bundle.get(“pdus”);  
    4.         SmsMessage[] messages = new SmsMessage[pdus.length];  
    5.         for (int i = 0; i < pdus.length; i++)  
    6.             messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);  
    7.     }  
     每个SmsMessage对象包含SMS 消息的细节,包括源地址(手机号),时间和消息体。

    下面的例子演示了一个Broadcast Receiver实现了onReceive函数来检查新来的短信是否以@echo字符串开始,如果是,发送相同的文本给那个手机:
    Java代码  收藏代码
    1. public class IncomingSMSReceiver extends BroadcastReceiver  
    2. {  
    3.     private static final String queryString = “@echo “;  
    4.     private static final String SMS_RECEIVED = “android.provider.Telephony.SMS_RECEIVED”;  
    5.   
    6.     public void onReceive(Context _context, Intent _intent){  
    7.         if (_intent.getAction().equals(SMS_RECEIVED)){  
    8.             SmsManager sms = SmsManager.getDefault();  
    9.             Bundle bundle = _intent.getExtras();  
    10.             if (bundle != null){  
    11.                 Object[] pdus = (Object[]) bundle.get(“pdus”);  
    12.                 SmsMessage[] messages = new SmsMessage[pdus.length];  
    13.                 for (int i = 0; i < pdus.length; i++)  
    14.                     messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);  
    15.                     for (SmsMessage message : messages){  
    16.                         String msg = message.getMessageBody();  
    17.                         String to = message.getOriginatingAddress();  
    18.                         if (msg.toLowerCase().startsWith(queryString)){  
    19.                             String out = msg.substring(queryString.length());  
    20.                             sms.sendTextMessage(to, null, out, null, null);  
    21.                         }         
    22.                     }  
    23.                 }  
    24.             }  
    25.         }  
    26.     }  
     为了监听短信,使用Intent Filter来注册Broadcast Receiver,使其监听android.provider.Telephony.SMS_RECEIVED动作,如下面的片段所示:
    Java代码  收藏代码
    1. final String SMS_RECEIVED = “android.provider.Telephony.SMS_RECEIVED”;  
    2.   
    3. IntentFilter filter = new IntentFilter(SMS_RECEIVED);  
    4. BroadcastReceiver receiver = new IncomingSMSReceiver();  
    5.   registerReceiver(receiver, filter);  
     
     
     
    其他:
    a、广播信息
                 在Android中,Broadcast是一种广泛运用在应用程序之间异步传输信息的机制。Android系统通过发出广播消息,来通知各应用组件一些系 统事件,如地域变换、电量不足、来电信息等,这些消息通常称为系统消息。第三方应用也可以广播消息,这些消息称为自定义消息。
             广播消息在本质上就是一个Intent对象。
               
                 BroadcastReceiver用于接收并处理广播消息。不管是系统消息还是自定义消息,都可以通过BroadcastReceiver来进行处理。形象的比喻,Intent是一种一对一的通信,广播消息是一种一对多的通信。
    b、 广播消息的处理流程
                对于广播消息的处理,大致要经过消息发送、BroadcastReceiver注册和消息处理三个环节。
    c、消息发送
                广播消息的实质就是一个Intent对象。使用sendBroadcast ()或sendStickyBroadcast()方法发出去的Intent,所有满足条件的BroadcastReceiver都会随机地执行其onReceive()方法;
            sendOrderBroadcast ()发出去的Intent,会根据BroadcastReceiver注册时Intent Filter 设置的优先级的顺序来执行,相同优先级的BroadcastReceiver则是随机执行。
            sendStickyBroadcast ()方法主要的不同的是,Intent在发送后一直存在,并且在以后调用registerReceiver注册相匹配的BroadcastReceiver时会把这个Intent直接返回。
    d、注册BroadcastReceiver
                 注册BroadcastReceiver有两种方式:
                 一种方式是,静态地在AndroidManifest.xml中用<receiver>标签声明,并在标签内用<intent-filter>标签设置过滤器
                  另一种方式是,动态在代码中先定义并设置好一个Intent Filter 对象,然后再需要注册的地方调用Context.registerReceiver(BroadcastReceiver,intentFilter)方 法,如果取消时就调用Context.unregisterReceiver(BroadcastReceiver)方法。如果用动态注册 BroadcastReceiver的Context对象被销毁时,BroadcastReceiver也就自动取消注册了。
              根据Activity组件的生命周期,通常在onResume中注册BroadcastReceiver,在onPause中取消BroadcastReceiver。
    e、处理消息
                 当广播消息发送以后,所有已经注册的BroadcastReceiver会检查注册时的Intent Filter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。另外,若在使用 sendBroadcast()的方法是指定了接收权限,则只有在AndroidManifest.xml中用标记<uses- permission>声明了拥有此权限的BroadcastReceiver才会有可能接收到发送来的Broadcast。
               
                 一个BroadcastReceiver可以处理多个广播消息,具体做法为在onReceive()方法调用Intent参数的getAction判断传进来的动作,即可进行不同的处理。
    f、处理系统广播消息
                  在广播消息中,有一类特殊的广播消息,它们特殊在只能由Android系统发出,这类广播消息称为系统广播。
                 ACTION_TIME_TICK  系统时间已经改变。该事件每分钟被广播一次,只能通过动态注册BroadcastReceiver来响应。
                 ACTION_TIME_CHANGED  系统时间被设置
                 ACTION_TIMEZONE_CHANGED  系统时区被改变
                 ACTION_BOOT_COMPLETED    系统启动完成
                 ACTION_PACKAGE_ADDED    新的应用程序被安装
                 ACTION_PACKAGE_CHANGED  应用程序被改变
                 ACTION_PACKAGE_REMOVED  应用程序被卸载
                 ACTION_PACKAGE_RESTARTED  应用程序被重新启动
                 ACTION_PACKAGE_DATA_CLEARED  应用程序数据被清空
                 ACTION_UID_REMOVED  用户ID被删除
                 ACTION_BATTERY_CHANGED 点量信息改变
                 ACTION_POWER_CONNECTED  外接电源被连通
                 ACTION_POWER_DISCONNECTED 外接电源被断开
                 ACTION_SHUTDOWN    系统关闭
                静态注册BroadcastReceiver 很简单,需要在AndroidManifest文件中增加一个receiver节点,并且在节点中嵌套一个intent-filter来声明组件响应的 Intent对象的属性,在autorun例子中,为系统广播android.intent.action.BOOT_COMPLETED的应用权限的声 明。
    g、深入消息处理
                 广播消息的发送方式由多种:
                 无序广播
                 有序广播
                 持续广播
    h、BroadcastReceiver的生命周期
                BroadcastReceiver 的onReceive()方法执行完成后,BroadcastReceiver的实例就会被销毁。如果onReceive()方法在10s内没有执行完 毕,Android会认为改程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否则会弹出“Application NoResponse”对话框。特别说明的是,这里不能使用子线程来解决 ,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时它所在的进程很容易在系统需要内存时被优先杀死,因为它属于空进程。
                  

    具体实例:
    http://www.apkbus.com/forum.php?mod=viewthread&tid=4406
    http://www.apkbus.com/forum.php?mod=viewthread&tid=19029&reltid=4406&pre_thread_id=0&pre_pos=1&ext=

    http://www.cnblogs.com/wangtianxj/archive/2010/01/20/1652480.html
     
  • 相关阅读:
    结对编程作业——毕设导师智能匹配
    结对项目之需求分析与原型设计
    Excel绘制之甘特图
    Excel绘图之数据波动条形图
    Excel绘图之漏斗图
    Excel绘图之四象限散点图
    软件工程实践总结
    发送手机验证码
    个人作业——软件产品案例分析
    用例图
  • 原文地址:https://www.cnblogs.com/xgjblog/p/3927795.html
Copyright © 2011-2022 走看看