• android广播机制


      

    Android开发之广播机制

    /*

     *  Android开发之广播机制

     *  北京Android俱乐部群:167839253

     * Created on: 2012-7-31

     * Author: blueeagle

     *  Email:liujiaxiang@gmail.com

     */

    在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。这个广播跟我们传统意义中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。

    什么是Broadcast Receiver

    BroadcastReceiver是Android应用程序中的第三个组件。Broadcast Reciver和事件处理机制类似,不同的是事件处理机制是应用程序组件级别的,比如一个按钮的OnClickListener事件,只能够在一个应用程序中处理。而广播事件处理机制是系统级别的,不同的应用程序都可以处理广播事件。

    如何使用Broadcast Receiver

    可以通过构建Intent对象,然后调用sendBroadcast()方法将广播发出。事件的接受是通过一个继承自BroadcastReceiver的类来实现的。继承后重写onReceiver()方法,在该方法中响应事件。当然不能忘记在AndroidManifest.xml文件中注册BroadcastReceiver

    一般继承自BroadcastReceiver的类,是我们根据自己的需求所自定义的。这个自定义的类的作用,就是用来处理android当中所发出的广播事件。也就是说,Android操作系统中发出的广播,由BroadcastReceiver这个类来接收。接收到以后,就会调用这个类中的onReceive()方法来进行处理。那么,在Android系统中,有很多的广播,如何才能确定,一个receiver负责接收什么类型的广播呢?对了。这就是要去书写AndroidManifest.xml文件。我们需要在AndroidManifest.xml里进行注册,将receiver注册到应用程序中。这个receiver应该接收什么类型的事件是由Intent-filter来决定的。

    对于onReceive方法,一旦方法返回。系统就会认为对象已经被完成。从而不再是活动状态。

    按照上述说明。简单的看一个例子,代码如下:

     

    [java] view plaincopy
     
    1. public class BroadcastReceiverTest extends Activity {  
    2.     private Button myButton;  
    3.     @Override  
    4.     public void onCreate(Bundle savedInstanceState) {  
    5.         super.onCreate(savedInstanceState);  
    6.         setContentView(R.layout.main);  
    7.          
    8.         myButton = (Button)findViewById(R.id.myButton);  
    9.         myButton.setOnClickListener(newButton.OnClickListener(){  
    10.            @Override  
    11.            public void onClick(View v) {  
    12.               Intent myIntent = new Intent();  
    13.                myIntent.setAction(myIntent.ACTION_EDIT);  
    14.               BroadcastReceiverTest.this.sendBroadcast(myIntent);//发送广播  
    15.            }  
    16.         });  
    17.     }  
    18. }  


    需要编写BroadcastReceiver类,代码如下:

     

    [java] view plaincopy
     
    1. public class ReceiverTest extends BroadcastReceiver {  
    2.     public ReceiverTest(){  
    3.        System.out.println("ReceiverTest");  
    4.     }  
    5.     @Override  
    6.     public void onReceive(Context arg0, Intent arg1) {  
    7.        System.out.println("onReceive");        
    8.     }  
    9. }  

    在AndroidManifest.xml中注册的代码如下:

     

    [html] view plaincopy
     
    1. <receiver  
    2.         android:label="@string/app_name"  
    3.         android:name=".ReceiverTest" >  
    4.          <intent-filter >  
    5.              <action android:name="android.intent.action.EDIT" />  
    6.          </intent-filter>  
    7.      </receiver>  

    编译完成之后,我们在控制台会得到如图所示的结果:

    如果连续按两次按钮,则会出现两次。如图所示:

    在上面的例子中,Intent的Action类型为ACTION_EDIT,而在AndroidManifest.xml中注册的receiver类型也是edit,<actionandroid:name="android.intent.action.EDIT"/>

    ,这就表明这两个Action进行了匹配。即执行了sendBroadcast方法之后,类型为edit的receiver就可以进行接收了。类型匹配成功的话,才会生成receiver的对象,从而调用onReceiver方法。上文中已经谈到,每次接收广播都会生成一个新的receiver对象。在处理完毕之后,这个对象就不会再被使用了。

    注册Broadcast Receiver的方法

           BroadcastReceiver能够监听被广播出来的对象,一般是会用Intent来进行广播。那么,达到能够监听的目的,则BroadcastReceiver必须进行注册。注册方法有两种:

    在AndroidManifest.xml文件中进行注册:

    这里面需要注意一点的是,如果我在AndroidManifest.xml文件中进行注册BroadcastReceiver的话,无论这个BroadcastReceiver所在的应用程序是运行状态还是关闭状态,这个BroadcastReceiver都是活动的,都可以接收到广播的事件。例如,短信息的接收,电池耗电量的显示等应用程序。我们在待机状态时需要监听这些状态,但是我们不可能一直打开应用程序。

    在应用程序的代码中进行注册:

           当我们需要更新Activity里面的控件的状态的时候,则需要在应用程序的代码中进行注册,这个时候我们如果在AndroidManifest.xml中注册的话就不太合适了。因为只有我们在Activity能看到的时候才进行更新,而Activity看不见的时候,这个BroadcastReceiver就应该关闭。否则会浪费各种资源。因此,这个时候就需要在应用程序的代码中进行注册。在Activity启动以后注册BroadcastReceiver,在Activity不可见后取消注册。

           注册的代码很简单就是registerReceiver(receiver,filter);

    相应的,取消注册的代码为unregisterReciver(receiver);

           参数receiver表示一个BroadcastReceiver对象( TheBroadcastReceiver to handle the broadcast.);filter表示一个Intent-filter对象(      Selectsthe Intent broadcasts to be received.),与我们在AndroidManifest.xml 文件中所使用的Intent-filter标签的作用是一样的。后面会讨论到如何创建一个Intent-filter对象。

           下面用手机接收信息这个例子来说明。对应代码如下:

     

    [java] view plaincopy
     
    1. public class BroadcastReceiverTest extends Activity {  
    2.     private Button myRegisterbtn;  
    3.     private Button myUnregisterbtn;  
    4.     private SMSReceiver myMessageReceiver;  
    5.     private static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";  
    6.     private static final String EDIT_ACTION = "android.intent.action.EDIT";  
    7.     @Override  
    8.     public void onCreate(Bundle savedInstanceState) {  
    9.         super.onCreate(savedInstanceState);  
    10.         setContentView(R.layout.main);  
    11.          
    12.         myRegisterbtn = (Button)findViewById(R.id.registerbtn);  
    13.         myUnregisterbtn = (Button)findViewById(R.id.unregisterbtn);  
    14.         myRegisterbtn.setOnClickListener(newmyRegisterListener());  
    15.         myUnregisterbtn.setOnClickListener(newmyUnregisterListener());  
    16.     }  
    17.     class myRegisterListener implements OnClickListener{  
    18.        @Override  
    19.        public void onClick(View v) {  
    20.            myMessageReceiver = new SMSReceiver();  
    21.            //生成一个BroadReceiver对象  
    22.            IntentFilter myFilter = new IntentFilter();  
    23.            //生成一个IntentFilter对象  
    24.            myFilter.addAction(SMS_ACTION);  
    25.            //为IntentFilter添加一个Action  
    26.            BroadcastReceiverTest.this.registerReceiver(myMessageReceiver, myFilter);  
    27.        }  
    28.        //整个操作完成了BroadcastReceiver的注册。  
    29.     }  
    30.     class myUnregisterListener implements OnClickListener{  
    31.        @Override  
    32.        public void onClick(View v) {  
    33.            BroadcastReceiverTest.this.unregisterReceiver(myMessageReceiver);  
    34.            //将BroadcastReceiver对象在系统中解除注册  
    35.        }  
    36.     }  
    37. }  

    代码很简单,就是定义了两个按钮,其中一个是将BroadcastReceiver绑定到应用程序中,另一个则是解除BroadcastReceiver在应用程序中的绑定。相应的,我们还需要将接收器的类编写出来,为了方便测试,我们只在接收器类里编写一个打印输出,代码如下:

     

    [java] view plaincopy
     
    1. public class SMSReceiver extends BroadcastReceiver {  
    2.     @Override  
    3.     public void onReceive(Context context, Intent intent) {  
    4.        System.out.println("onReceivestart");  
    5.         }  
    6. }  

    当然,我们这里是在应用程序中注册的BroadcastReceiver,所以就不用在AndroidManifest.xml文件中再去注册一次了。(读者可以尝试着仍然去AndroidManifest.xml文件中注册,看看会发送什么现象。)运行程序,并且点击注册按钮,然后利用DDMS来给模拟器发送一条短信。如图所示:

    当我们点击完Send按钮后,查看控制台,则会发现“onReceive start”已经被打印出来了,如下图所示:

    这就意味着,接收器在过滤到发送信息这样的事件后,接收到了广播。至此,BroadcastReceiver的两种注册方式就讲完了。

    讲完这两种方式后,读者可能会有一系列疑问。那就是,为什么我这个action是android.provider.Telephony.SMS_RECEIVED的时候,发送一个消息,对应的接收器就能够接收到广播,如果我的action不是这个,那么发送的广播还会被接收吗?又该怎么样确定到底一个action对应什么操作?从而才能够被广播接收器接收到。Android系统中又多少内置的这种action?我们能不能自定义一个action?如果可以的话如何定义呢?

    首先,我们来考察一下Android内置的Broadcast Actions。

    Android内置的Broadcast Actions

    在Android平台中,内置了很多Action,用于帮助开发者监听手机上所发生的各种事件。下面给出几个内置的BroadcastAction的例子:

    android.intent.action.BATTERY_CHANGED 

    充电状态,或者电池的电量发生变化 

    android.intent.action.SCREEN_ON 

    屏幕已经被打开 

    android.intent.action.PACKAGE_REMOVED 

    设备上删除了一个应用程序包 

    android.intent.action.TIME_TICK  

    当前时间已经变化(正常的时间流逝) 

    如果要查询BroadcastAction的完整列表,可以在官方SDK的帮助文档里面找到Intent类,在常量定义的解释中,去找Broadcast Action开头的信息就可以了。例如我们找到String类型的常量:ACTION_BATTERY_LOW,后面的解释是以“Broadcast Action”开头的。

    String      ACTION_BATTERY_LOW    Broadcast Action: Indicates low batterycondition on the device.

    一般来说,Android操作系统给我们提供的内置的Broadcast Action是够用的,当然我们也可以进行自定义Broadcast的Action。

    自定义Broadcast Action

    自定义Broadcast Actions其实就是自定义一个字符串常量。然后将这个常量广播出去,接收的地方再接收这个常量就可以了。下面利用代码来说明自定义BroadcastAction,同时,这里还将BroadcastReceiver和负责广播的工程分开成两个工程来说明,对于不同工程之间的广播接收的处理方式。代码如下:

     

    [java] view plaincopy
     
    1. public class MyBroadcast extends Activity {  
    2.     public static final String NEW_BROADCAST = "com.todd.NEW_BROADCAST";   
    3.     /* 这个静态常量字符串可以自己随便定义,代表自定义的action*/  
    4.     @Override  
    5.     public void onCreate(Bundle savedInstanceState) {  
    6.         super.onCreate(savedInstanceState);  
    7.         setContentView(R.layout.main);  
    8.         Button mybutton =(Button)findViewById(R.id.mybutton);  
    9.         mybutton.setOnClickListener(newButton.OnClickListener() {  
    10.             public void onClick(View v) {  
    11.             Intent myIntent = new Intent(NEW_BROADCAST);  
    12.             myIntent.putExtra("MSG""地瓜地瓜,我是土豆!");  
    13.             myIntent.setAction(NEW_BROADCAST);  
    14.             sendBroadcast(myIntent);  
    15.             }  
    16.             });  
    17.     }  
    18. }  

    XML文件中只需要定义一个按钮

     

    [html] view plaincopy
     
    1. <Button   
    2.     android:id="@+id/mybutton"  
    3.     android:layout_width="fill_parent"  
    4.     android:layout_height="wrap_content"  
    5.     android:text="发送广播"  
    6.     />  

    然后再建立一个工程,作为接收的工程,这个工程负责接收广播工程广播出来的数据。代码如下:

     

    [java] view plaincopy
     
    1. public class MyReceiver extends BroadcastReceiver {  
    2.     /** Calledwhen the activity is first created. */  
    3.     @Override  
    4.     public void onReceive(Context context, Intent intent) {  
    5.        // TODO Auto-generatedmethod stub  
    6.        String message = intent.getExtras().getString("MSG");  
    7.        Toast.makeText(context, message, Toast.LENGTH_LONG).show();  
    8.        System.out.println(message);  
    9.     }  
    10. }  

    到这里还不算完。需要有一个注册的过程。注册的过程,就是让接收工程知道我要接收来自哪一个Intent的数据。

    在Androidmanifest.xml中注册如下:

     

    [html] view plaincopy
     
    1. <receiver android:name=".MyReceiver">  
    2.     <intent-filter>  
    3.         <action android:name="com.todd.NEW_BROADCAST" />  
    4.     </intent-filter>  
    5. </receiver>  

    这样就把"com.todd.NEW_BROADCAST"动作注册到了接收工程中。如此,接收工程完毕。

    但是这样就结束了吗?还没有。如果此时编译后,广播工程没有任何问题,但是接收工程会出错,classcast的错误。这是因为,我们在编译接收工程的时候,没有给接收工程一个Activity用于显示接收的信息。因此,我们需要定义一个Activity.代码如下:

     

    [java] view plaincopy
     
    1. public class IntentRes extends Activity {  
    2.     @Override  
    3.     public void onCreate(Bundle savedInstanceState) {  
    4.         super.onCreate(savedInstanceState);  
    5.         setContentView(R.layout.main);  
    6.     }  
    7. }  

    当然,在相应的AndroidManifest.xml文件中要修改,写为:

     

    [html] view plaincopy
     
    1. <activity android:name=".IntentRes"  
    2.           android:label="@string/app_name">  
    3.     <intent-filter>  
    4.         <action android:name="android.intent.action.MAIN" />  
    5.         <category android:name="android.intent.category.LAUNCHER" />  
    6.     </intent-filter>  
    7. </activity>  

    至此,就完成了广播和接收。他们位于不同的工程中。

  • 相关阅读:
    P1215 [USACO1.4]母亲的牛奶 Mother's Milk
    P2966 [USACO09DEC]牛收费路径Cow Toll Paths
    P2419 [USACO08JAN]牛大赛Cow Contest
    1085 数字游戏
    P1983 车站分级
    P1346 电车(dijkstra)
    P1196 银河英雄传说(加权并查集)
    P1195 口袋的天空
    3027 线段覆盖 2
    codevs 1214 线段覆盖/1643 线段覆盖 3
  • 原文地址:https://www.cnblogs.com/stallran/p/3668569.html
Copyright © 2020-2023  润新知