【Android开发日记】之入门篇(六)——Android四大组件之Broadcast Receiver

广播接受者是做为系统的监听者存在着的,它能够监听系统或系统中其余应用发生的事件来作出响应。如设备开机时,应用要检查数据的变化情况,此时就能够经过广播来把消息通知给用户。又如网络状态改变时,电量变化时均可以经过广播来通知用户。要作比喻的话,广播就像是咱们的感官,可以有效且快速的从外界获取信息来反馈给自身。

1、广播的功能和特征

  1. 广播的生命周期很短,通过 调用对象—实现onReceive—结束 整个过程就结束了。从实现的复杂度和代码量来看,广播无疑是最迷你的Android 组件,实现每每只需几行代码。广播对象被构造出来后一般只执行BroadcastReceiver.onReceive方法,便结束了其生命周期。因此有的时候咱们能够把它当作函数看也未必不可。
  2. 和全部组件同样,广播对象也是在应用进程的主线程中被构造,因此广播对象的执行必须是要同步且快速的。也不推荐在里面开子线程,由于每每线程还未结束,广播对象就已经执行完毕被系统销毁。若是须要完成一项比较耗时的工做 , 应该经过发送 Intent 给 Service, 由 Service 来完成。
  3. 每次广播到来时 , 会从新建立 BroadcastReceiver 对象 , 而且调用 onReceive() 方法 , 执行完之后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕, Android 会认为该程序无响应。

2、广播事件监听的两种方法android

使用广播进行事件监听有两种方法,静态注册和动态注册,又或者称冷插拔和热插拔。静态注册就是将广播接收器的相关信息写在应用的配置文件中。当有广播事件发生时,组件管理服务就会从安装包管理服务中获取已安装应用的广播组件信息。动态注册则是经过Context.registerReceiver和Context.unregisterRecever,动态将广播接收器与所须要监听的事件绑定。web

  1. 静态注册
    首先是在应用的配置文件中写入注册消息,一样是跟其余组件同样写在application标签以内
    <receiver android:name=".ColdReceiver"><!-- 你的Receiver名称 -->  
       <intent-filter>  
          <action android:name="android.intent.action.COLD_BROADCAST"/>  <!-- 你广播要接受的intent名称 -->
          <category android:name="android.intent.category.DEFAULT" />  
       </intent-filter>  
    </receiver>

    而后咱们建一个ColdReceiver的类,继承BroadcastReceiver,里面代码以下
    安全

    public class ColdReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            //跳转到service中
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(1);
            //开启service
            context.startService(intent);
            //日志打印
            Log.d("TEST","静态注册");
        }
    
    }

    上面的Service启动看到了吗,这里我用了上次说过的快捷跳转。其中service的配置和内容以下
    网络

    <service android:name=".BroadcastService"><!-- 你自定义的service文件   (在<application></application>里面加)-->
            <intent-filter>
                    <action android:name="android.intent.action.BroadcastService" /><!-- 用intent启动时的快捷名(也能够用常规的方式启动) -->
                    <category android:name="android.intent.category.default" />
            </intent-filter>
            </service>
    View Code
     1 public class BroadcastService extends Service{
     2 
     3     @Override
     4     public IBinder onBind(Intent intent) {
     5         // TODO Auto-generated method stub
     6         return null;
     7     }
     8     
     9     @Override
    10     public void onCreate() {
    11         //开启服务时会首先调用该方法
    12         super.onCreate();
    13     }
    14 
    15     @Override
    16     public int onStartCommand(Intent intent, int flags, int startId) {
    17         //根据每次intent传过来的信息进行判断来显示不一样信息
    18         switch(intent.getFlags()){
    19             case 1:{
    20                 Toast.makeText(getApplicationContext(), "静态注册", Toast.LENGTH_SHORT).show();
    21                 break;
    22             }
    23             case 2:{
    24                 Toast.makeText(getApplicationContext(), "动态注册", Toast.LENGTH_SHORT).show();
    25                 break;
    26             }
    27             case 3:{
    28                 Toast.makeText(getApplicationContext(), "普通广播", Toast.LENGTH_SHORT).show();
    29                 break;
    30             }
    31             case 4:{
    32                 Toast.makeText(getApplicationContext(), "有序广播", Toast.LENGTH_SHORT).show();
    33                 break;
    34             }
    35         }
    36         return START_STICKY;
    37     }
    38 
    39     @Override
    40     public void onDestroy() {
    41         // 中止service后会调用此方法
    42         Log.d("TEST", "destroy");
    43         super.onDestroy();
    44     }
    45 
    46 }
    View Code

    那么静态广播的建立就完成了,简单吧,就两个步骤,一是配置广播,二是继承BroadcastReceiver,重写里面的onReceive函数。
    接下来咱们在新建一个工程来检测广播是否能够响应消息。(检测应用的代码所有都在下方,而且不用再作更改了)
    app

     1 public class MainActivity extends Activity implements OnClickListener{
     2 
     3     private Button b1,b2,b3,b4;
     4     private Intent intent;
     5     @Override
     6     protected void onCreate(Bundle savedInstanceState) {
     7         super.onCreate(savedInstanceState);
     8         setContentView(R.layout.activity_main);
     9         intent = new Intent();
    10         //得到界面的控件
    11         b1 = (Button) findViewById(R.id.button1);
    12         b1.setOnClickListener(this);
    13         b2 = (Button) findViewById(R.id.button2);
    14         b2.setOnClickListener(this);
    15         b3 = (Button) findViewById(R.id.button3);
    16         b3.setOnClickListener(this);
    17         b4 = (Button) findViewById(R.id.button4);
    18         b4.setOnClickListener(this);
    19         Log.d("TEST","===初始化完成===");
    20     }
    21     
    22     @Override
    23     public void onClick(View v) {
    24         // TODO Auto-generated method stub
    25         switch(v.getId()){
    26             case R.id.button1:{//发送到静态注册广播
    27                 intent = new Intent("android.intent.action.COLD_BROADCAST");  
    28                 sendBroadcast(intent);
    29                 //intent.putExtra("msg", "hello coldreceiver.");  
    30                 break;
    31             }
    32             case R.id.button2:{//发送到动态注册广播
    33                 intent = new Intent("android.intent.action.HOT_BROADCAST");  
    34                 //intent.putExtra("msg", "hello hotreceiver.");  
    35                 sendBroadcast(intent);
    36                 break;
    37             }
    38             case R.id.button3:{//普通广播
    39                 intent = new Intent("android.intent.action.NORMAL_BROADCAST");  
    40                 sendBroadcast(intent);
    41                 break;
    42             }
    43             case R.id.button4:{//有序广播
    44                 intent = new Intent("android.intent.action.SORT_BROADCAST");  
    45                 sendOrderedBroadcast(intent, "scott.permission.SORT_BROADCAST_PERMISSION");  
    46                 break;
    47             }
    48         }
    49     }
    50     
    51     public void show(String str){
    52         Toast.makeText(this, str, Toast.LENGTH_LONG).show();
    53     }
    54 
    55     @Override
    56     protected void onDestroy() {
    57         // TODO Auto-generated method stub
    58         super.onDestroy();
    59     }
    60 }
    View Code

    ok,将两个应用都安装到设备上,启动测试用的应用,点击第一个按钮,运行的效果以下

    同时,会出现"静态注册"的Toast(不方便截图)。能够看出静态注册广播可以跨应用来响应信息,这都要归功于安卓上的组件管理服务,它会读取每一个应用的配置文件,而后获取里面的组件信息,每当有消息响应时,组件管理服务会从中查找有没有须要调用的组件,并判断是否进行执行
    异步

  2. 动态注册
    动态注册也能够分红两部分,一在代码中进行动态注册,二仍是继承BroadcastReceiver,重写里面的onReceive函数。
    咱们在广播应用中新建一个
    HotReceiver,继承BroadcastReceiver
    public class HotReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            //String msg = intent.getStringExtra("msg");  
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(2);
            context.startService(intent);
            Log.d("TEST","动态注册");
        }
    
    }

    在Activity中进行动态注册
    ide

    public class MainActivity extends Activity {
    
        private HotReceiver receiver;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            //动态注册广播
            //新建一个广播对象
            receiver = new HotReceiver();  
            //新建一个intent管理机制,(功能是对组件进行过滤,只获取须要的消息)
            IntentFilter filter = new IntentFilter(); 
            //添加白名单(只获取该动做的信息)
            filter.addAction("android.intent.action.HOT_BROADCAST");          
            //与广播绑定,进行注册
            registerReceiver(receiver, filter);
        }
    
        @Override
        protected void onDestroy() {
            //取消注册,必定要记得,否则系统会报错误
            unregisterReceiver(receiver);
            stopService(new Intent("android.intent.action.BroadcastService"));
            super.onDestroy();
        }
    
    }

    ok,再使用测试应用来检查一下效果,注意步骤,安装好广播应用打开,不要让它退出,切换到测试用的广播,点击第二个按钮。
    函数

    测试成功。那么咱们关掉广播应用在测试一下,会发现不会再出现动态注册的打印消息。这说明动态注册的广播是与Activity绑定的,当Activity销毁时,广播也会被销毁。
    在Android中,不少时候最好是使用动态注册的方式使用广播,好比时间变化事件,电量变动事件等,这些事件触发率过高,若是使用静态注册,会致使进程频繁的被构造和销毁从而影响整个系统的效率。
    测试

3、广播的两种类型this

  1. 普通广播
    普通广播对于多个接收者来讲是彻底异步的,一般每一个接收者都无需等待便可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者没法终止广播,即没法阻止其余接收者的接收动做。
    接下来咱们新建三个广播来进行验证。
    public class NormalReceiver1 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(3);
            context.startService(intent);
            Log.d("TEST","普通广播1");
            abortBroadcast();
        }
    
    }
    public class NormalReceiver2 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(3);
            context.startService(intent);
            Log.d("TEST","普通广播2");
            abortBroadcast();
        }
    
    }
    public class NormalReceiver3 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(3);
            context.startService(intent);
            Log.d("TEST","普通广播3");
            abortBroadcast();
        }
    
    }
    <receiver android:name=".NormalReceiver1">  
                <intent-filter>  
                    <action android:name="android.intent.action.NORMAL_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver> 
            <receiver android:name=".NormalReceiver2">  
                <intent-filter>  
                    <action android:name="android.intent.action.NORMAL_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver> 
            <receiver android:name=".NormalReceiver3">  
                <intent-filter>  
                    <action android:name="android.intent.action.NORMAL_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver>
    Xml Code

    安装完毕后,咱们点击检测应用的第三个按钮,能够看到

    abortBroadcast()做用是阻断广播向下一级传播,显然在这里不起做用,并会让系统报错。因此若是要让广播有必定的优先级进行传播就要使用到有序广播。
  2. 有序广播
    有序广播经过调用sendOrderedBroadcast函数进行发送。它每次只发送到优先级较高的接收者那里,而后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。在有序广播的传递过程当中,每一个执行中的触发器组件均可以经过BroadcastReceiver.setResult等函数附加额外的数据,而下一个广播则可使用这些数据(BroadcastReceiver.getResultData)。这样能够构成一个消息数据处理链。
    为了保证某一事件必定会被处理,能够指明默认的广播接收器(Final Receiver)。
    同样的,新建三个广播样例
    public class SortReceiver1 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            //String msg = intent.getStringExtra("msg");  
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(4);
            context.startService(intent);
            Log.d("TEST","有序广播1");
            abortBroadcast();
        }
    
    }
    public class SortReceiver2 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            //String msg = intent.getStringExtra("msg");  
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(4);
            context.startService(intent);
            Log.d("TEST","有序广播2");
        }
    
    }
    public class SortReceiver3 extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            //String msg = intent.getStringExtra("msg");  
            intent = new Intent("android.intent.action.BroadcastService"); 
            intent.addFlags(4);
            context.startService(intent);
            Log.d("TEST","有序广播3");
        }
    
    }
    <receiver android:name=".SortReceiver1">  
                <intent-filter android:priority="1000">  
                    <action android:name="android.intent.action.SORT_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver> 
            <receiver android:name=".SortReceiver2">  
                <intent-filter android:priority="999">  
                    <action android:name="android.intent.action.SORT_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver> 
            <receiver android:name=".SortReceiver3">  
                <intent-filter android:priority="998">  
                    <action android:name="android.intent.action.SORT_BROADCAST"/>  
                    <category android:name="android.intent.category.DEFAULT" />  
                </intent-filter>  
            </receiver>
    View Code

    咱们看到,如今这三个接收者的<intent-filter>多了一个android:priority属性,而且依次减少。这个属性的范围在-1000到1000,数值越大,优先级越高。
    一样发送广播的代码也是不同的

    sendOrderedBroadcast(intent, "scott.permission.SORT_BROADCAST_PERMISSION");

    注意,使用sendOrderedBroadcast方法发送有序广播时,须要一个权限参数,若是为null则表示不要求接收者声明指定的权限,若是不为 null,则表示接收者若要接收此广播,需声明指定权限。这样作是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用多是具备拦截垃圾短信 的功能,当短信到来时它能够先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。

    因此咱们在AndroidMainfest.xml中定义一个权限,并得到权限:(是要在广播的应用中声明)

    <permission android:protectionLevel="normal"  
                android:name="scott.permission.SORT_BROADCAST_PERMISSION" />
    <uses-permission android:name="scott.permission.SORT_BROADCAST_PERMISSION" />

    (这里不是写在application内部,而是同application同级)

    运行后只会出现这么一个消息:

    由于在第一个广播出咱们就终止了广播的继续传递,因此就只会出现这么一条打印消息。

4、形形色色的广播

在android中有不少系统自带的intent.action,经过监听这些事件咱们能够完成不少功能。

  1. 开机:
    String BOOT_COMPLETED_ACTION 广播:在系统启动后。这个动做被广播一次(只有一次)。监听: “android.intent.action.BOOT_COMPLETED”
  2. 电话拨入:
    String ANSWER_ACTION 动做:处理拨入的电话。监听: “android.intent.action.ANSWER”
  3. 电量变化:
    String BATTERY_CHANGED_ACTION 广播:充电状态,或者电池的电量发生变化。监听: “android.intent.action.BATTERY_CHANGED”
  4. 日期改变:
    String DATE_CHANGED_ACTION 广播:日期被改变。 监听:“android.intent.action.DATE_CHANGED”
  5. 取消更新下载:
    String FOTA_CANCEL_ACTION 广播:取消全部被挂起的 (pending) 更新下载。 监听:“android.server.checkin.FOTA_CANCEL”
  6. 更新开始安装:
    String FOTA_READY_ACTION 广播:更新已经被下载 能够开始安装。监听 “android.server.checkin.FOTA_READY”
  7. 主屏幕:
    String HOME_CATEGORY 类别:主屏幕 (activity)。设备启动后显示的第一个 activity。 监听:"android.intent.category.HOME”
  8. 新应用:
    String PACKAGE_ADDED_ACTION 广播:设备上新安装了一个应用程序包。监听: “android.intent.action.PACKAGE_ADDED”
  9. 删除应用:
    String PACKAGE_REMOVED_ACTION 广播:设备上删除了一个应用程序包。监听: “android.intent.action.PACKAGE_REMOVED”
  10. 屏幕关闭:
    String SCREEN_OFF_ACTION 广播:屏幕被关闭。监听: “android.intent.action.SCREEN_OFF”
  11. 屏幕开启:
    String SCREEN_ON_ACTION 广播:屏幕已经被打开。 监听:“android.intent.action.SCREEN_ON”
  12. 时区改变:
    String TIMEZONE_CHANGED_ACTION 广播:时区已经改变。监听: “android.intent.action.TIMEZONE_CHANGED”
  13. 时间改变:
    String TIME_CHANGED_ACTION 广播:时间已经改变(从新设置)。 “android.intent.action.TIME_SET”
  14. 时间流逝:
    String TIME_TICK_ACTION 广播:当前时间已经变化(正常的时间流逝)。 “android.intent.action.TIME_TICK”
  15. 进入大容量存储模式:
    String UMS_CONNECTED_ACTION 广播:设备进入 USB 大容量存储模式。 “android.intent.action.UMS_CONNECTED”
  16. 退出大容量存储模式:
    String UMS_DISCONNECTED_ACTION 广播:设备从 USB 大容量存储模式退出。 “android.intent.action.UMS_DISCONNECTED”
  17. 壁纸改变:
    String WALLPAPER_CHANGED_ACTION 广播:系统的墙纸已经改变。 “android.intent.action.WALLPAPER_CHANGED”
  18. web搜索:
    String WEB_SEARCH_ACTION 动做:执行 web 搜索。 “android.intent.action.WEB_SEARCH”
  19. 网络变化:
    String CONNECTIVITY_CHANGE_ACTION 动做:网络变化。“android.intent.action.CONNECTIVITY_CHANGE_ACTION”
广播自己的使用很简单,它所包含的内容也不多,最可能是要多记住几个系统经常使用的几个ACTION。可是结合广播来进行应用的开发却会给用户带来更好的体验,广播的使用会让用户以为开发者可以为用户考虑到各个状况的发生,这点每每可以留住大多数的用户。因此多考虑各类状况的发生,不要吝啬广播的使用 ,争取为用户留下一个好的印象吧。
 
资源下载:Demo
 
 ========================================
做者:cpacm
出处:(http://www.cpacm.net/2015/03/22/Android开发日记(四)——Android四大组件之Broadcast-Receiver/
相关文章
相关标签/搜索