• Android 广播机制


    一、Android广播机制概述

    Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。

    广播作为Android组件间的通信方式,可以使用的场景如下:

    1. 同一app内部的同一组件内的消息通信(单个或多个线程之间);
    2. 同一app内部的不同组件之间的消息通信(单个进程);
    3. 同一app具有多个进程的不同组件之间的消息通信;
    4. 不同app之间的组件之间消息通信;
    5. Android系统在特定情况下与App之间的消息通信。

    二、广播的分类

    • Normal Broadcast(普通广播):通常调用sendBroadcast(Intent)(Intent, String)方法发送
    • System Broadcast(系统广播):发生各种事件时,系统自动发送
    • Ordered Broadcast(有序广播):调用sendOrderedBroadcast(Intent, String)方法发送
    • Local Broadcast(本地广播):调用LocalBroadcastManager.sendBroadcast(intent)方法发送
    • Sticky Broadcast(粘性广播):已弃用(API 21)

    1).Normal Broadcast:普通广播

    此处将普通广播界定为:开发者自己定义的intent,以context.sendBroadcast_"AsUser"(intent, ...)形式。具体可以使用的方法有:
    sendBroadcast(intent)
    sendBroadcast(intent,receiverPermission)
    sendBroadcastAsUser(intent,userHandler)
    sendBroadcastAsUser(intent,userHandler,receiverPermission)。
    普通广播会被注册了的相应的感兴趣(intent-filter匹配)接收,且顺序是无序的。如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限。

    • 发送示例如下:
    Intent intent = new Intent();
    intent.setAction(BROADCAST_ACTION);
    //最普通的发送方式
    sendBroadcast(intent);
    //附带权限的发送方式,声明此权限的BroadcastReceiver才能接收此广播
    sendBroadcast(intent,RECEIVER_PREMISSION);
    
    //以下两种不常见,是因为只有预装在系统映像中的程序才能使用,否则无法使用
    //指明接收人的发送方式
    sendBroadcastAsUser(intent,USER_HANDLER);
    //指明接收人以及对应权限的发送方式
    sendBroadcastAsUser(intent,USER_HANDLER,RECEIVER_PREMISSION);
    
    • 若被注册了的BroadCastReceiver注册的intentFilteraction与上述匹配,则会接收此广播,且顺序是无序的。如果发送时有相应的权限要求,则BroadCastReceiver只有拥有相应的权限才能接受。
    <receiver
        android:name=".MyBroadcastReceiver"
        android:permission="RECEIVER_PREMISSION">
        <intent-filter>
            <action android:name="BROADCAST_ACTION"/>
        </intent-filter>
    </receiver>

    2).System Broadcast: 系统广播

    Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。
    如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出。

    文末提供详细系统广播清单,不包含使用说明(位于SDK下boradcast_action.txt ),请自行查找Google官方文档

    3).Ordered broadcast:有序广播 

    有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其的主要发送方式变为:sendOrderedBroadcast(intent, receiverPermission, ...)。

    • 定义过程与普通广播一样,调用sendOrderedBroadcast(),同样也有对应的sendOrderedBroadcastAsUser()方法,只不过同样针对于预装在系统映像的应用。

    对于有序广播,其主要特点总结如下:
    1>多个具当前已经注册且有效的BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。

    1. priority值不同:由大到小排序
    2. priority值相同:动态注册优于静态注册

    2>先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。

    1. 按顺序接收
    2. 允许优先级高的BroadcastReceiver截断广播。
    3. 允许优先级高的BroadcastReceiver修改广播

    4).Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)

    5).Local Broadcast:App应用内广播(此处的App应用以App应用进程为界)

    Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:

    1.其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;

    2.其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。

    无论哪种情形,这些安全隐患都确实是存在的。由此,最常见的增加安全性的方案是:
    1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
    2.在广播发送和接收时,都增加上相应的permission,用于权限验证;
    3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
    App应用内广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App。实际的业务需求中,App应用内广播确实可能需要用到。同时,之所以使用应用内广播时,而不是使用全局广播的形式,更多的考虑到的是Android广播机制中的安全性问题。
    相比于全局广播,App应用内广播优势体现在:
    1.安全性更高;
    2.更加高效。
    为此,Android v4兼容包中给出了封装好的LocalBroadcastManager类,用于统一处理App应用内的广播问题,使用方式上与通常的全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将主调context变成了LocalBroadcastManager的单一实例。

    • 代码示例如下:
    //实例化MyBroadcastReceiver
    mBroadcastReceiver = new MyBroadcastReceiver();
    //实例化IntentFilter
    IntentFilter intentFilter = new IntentFilter();
    
    //得到LocalBroadcastManager实例
    LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
    
    //设置接收广播的类型
    intentFilter.addAction(BROADCAST_ACTION);
    
    //动态注册
    localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
    
    
    //取消注册
    localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
    

    三、广播接收者(BroadCastReceiver)的两种注册方式

    1).常驻型广播(静态注册)

    常驻型广播,这个广播接收者会在程序运行的整个过程中一直存在,不会被注销掉,当程序被杀掉后不会再接收到广播了。它的注册方式就是在你应用程序的AndroidManifast.xml 中进行注册,这种注册方式通常又被称作静态注册。这种方式可以理解为通过清单文件注册的广播是交给操作系统去处理的。在Manifest.xml中注册广播,是一种比较推荐的方法,因为它不需要手动注销广播(如果广播未注销,程序退出时可能会出错)。 

    例如:下边是注册的一些系统广播接收者

    首先写一个类继承自BroadCastReceiver。

    
    package com.example.mybroadcastreceiver;
     
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.widget.Toast;
     
    /**
     * 这是一个获取系统的广播。是一个接收拨打电话的广播
     * 在配置文件中配置了广播接收的过滤意图来实现注册
     * 这个广播是只有程序在运行就一直处于接收状态,当程序被杀死后就无法再接收到广播了
     * 
     *   <!-- 系统广播,接收打电话的广播 ,这个需要配置权限 -->
           <!--  <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> -->
            <receiver android:name="com.example.mybroadcastreceiver.OutCallReceiver" >
                <intent-filter>
                    <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                </intent-filter>
            </receiver>
     * @author Administrator
     *
     */
    public class OutCallReceiver extends BroadcastReceiver{
     
    	@Override
    	public void onReceive(Context context, Intent intent) {
    		/**
    		 * 这里是接收到广播后需要进行的操作都放在这里
    		 */
    		System.out.println("接收到打电话的广播了,可以在此做相应的操作");
    		Toast.makeText(context, "接收到打电话的广播了,可以在此做相应的操作", 1).show();
    	}
     
    }
    

    然后在清单文件中进行静态的注册配置。这样就完成了对接收拨打电话广播的注册,在整个程序运行的过程中,只要手机拨打电话了都能接收到这个广播,并会执行onReceive中的代码。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.mybroadcastreceiver"
        android:versionCode="1"
        android:versionName="1.0" >
     
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="19" />
        <uses-permission android:name="android.permission.RECEIVE_SMS"/>
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    	
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            
          <!--   这里将进入口的activity注释掉就会导致装完app后不会显示图标和界面,但是广播是能够接收到。很流氓。 -->
         <!--  4.0以后就不会出现这种情况,必须启动一次页面后才能完成广播的注册。如果想实现不启动页面运行广播,可以使用Service -->
            <activity
                android:name="com.example.mybroadcastreceiver.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
     
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
     
            <!-- 系统广播,接收打电话的广播 ,这个需要配置权限 -->
           <!--  <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> -->
            <receiver android:name="com.example.mybroadcastreceiver.OutCallReceiver" >
                <intent-filter>
                    <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                </intent-filter>
            </receiver>
            
            
         <!--    系统广播,接收收到短信的广播,这个需要配置权限 -->
         <!--  <uses-permission android:name="android.permission.RECEIVE_SMS"/> -->
            <receiver android:name="com.example.mybroadcastreceiver.SmSReceiver">
                <intent-filter >
                    <!-- 4.0以后不提示了,需要自己手动输入-->
                    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                </intent-filter>
            </receiver>
            
            <!--    系统广播,接收收到开机的广播,这个需要配置权限 -->
         <!--  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> -->
            <receiver android:name="com.example.mybroadcastreceiver.BootReceiver">
                <intent-filter >
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
            </receiver>
            
            
       <!--     系统广播,当有应用被安装、卸载、替换时 收到的广播-->
            <receiver android:name="com.example.mybroadcastreceiver.AppStatusReceiver">
                <intent-filter >
        <!--这个不是安装,安装时added <action android:name="android.intent.action.PACKAGE_INSTALL"/> -->
                    <action android:name="android.intent.action.PACKAGE_ADDED"/>
                    <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                    <action android:name="android.intent.action.PACKAGE_REPLACED"/>
                    <data android:scheme="package"/>
                </intent-filter>
            </receiver>
        </application>
     
    </manifest>

    注意:BroadcastReceiver作为内部类时,如要通过静态注册的方式在清单文件中注册,必须要声明为public static,否则会报错:

    没有public报错:java.lang.RuntimeException: Unable to instantiate receiver com.example.multibroadcastreceiver.MainActivity$ThirdBroadCast: java.lang.IllegalAccessException: access to class not allowed

    没有static报错:java.lang.InstantiationException: can't instantiate class com.taodian.evacuation.fragment.AlarmFragment$MessageReceiver; no empty constructor

    • AndroidManifest.xml文件中通过<receiver>进行注册
    • 规则及实例说明:
    <receiver
        //BroadcastReceiver子类的类名
        android:name="string"
    
        //是否使用该BroadcastReceiver
        android:enabled=["true" | "false"]
    
        //此broadcastReceiver能否接收其他App的发出的广播
        //其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false
        android:exported=["true" | "false"]
    
        android:icon="drawable resource"
        android:label="string resource"
    
        //具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收
        android:permission="string"
    
        //broadcastReceiver运行所处的进程。
        //默认为app的进程,可以指定独立的进程
        //Android四大基本组件都可以通过此属性指定自己的独立进程
        android:process="string">
    
        //指定此广播接收器将用于接收特定的广播类型
        //本例中给出的时系统开机后自身发出的广播
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
        </intent-filter>
    </receiver>

    以上述静态方法注册的MyBroadcastReceiver,在app首次启动时,系统或自动实例化MyBroadcastReceiver,并注册到系统中。 

    2).非常驻型广播(动态注册)

    非常驻型广播,是通过代码注册广播接收者的一种形式。代码注册时可以将广播接收者作为一个内部类写在Activity中,也可以重新写一个类继承自BroadCastReceiver,需要用代码注册(注册广播可以写在任意的地方,只有注册的广播接收者才能收到对应的广播),比如在 Activity 中的 onCreate 或者 onResume 中注册广播接收者,在 onDestory 中注销广播接收者。这样你的广播接收者就一个非常驻型的了,这种注册方式也叫动态注册。这种方式可以理解为通过代码注册的广播是和注册者关联在一起的。

    下面是在Activity中注册和注销广播接收者:

    package com.example.mybroadcastreceiver;
     
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.os.ResultReceiver;
    import android.support.v7.app.ActionBarActivity;
    import android.view.View;
    import android.widget.Toast;
     
    public class MainActivity extends ActionBarActivity {
     
    	
    	private static final String MY_BROADCAST_ACTION = "com.example.mybroadcastreceiver.my_broadcast_action";
    	private FirstBroadCast firstBroadCast;
    	private TwiceBroadCast twiceBroadCast;
    	private ThirdBroadCast thirdBroadCast;
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		firstBroadCast = new FirstBroadCast();
    		IntentFilter filter1 = new IntentFilter();
    		filter1.addAction(MY_BROADCAST_ACTION);
    		filter1.setPriority(1000);
    		registerReceiver(firstBroadCast, filter1);
    		
    		
    		twiceBroadCast = new TwiceBroadCast();
    		IntentFilter filter2 = new IntentFilter();
    		filter2.addAction(MY_BROADCAST_ACTION);
    		filter1.setPriority(5);
    		registerReceiver(twiceBroadCast, filter2);
    		
    		
    		thirdBroadCast = new ThirdBroadCast();
    		IntentFilter filter3 = new IntentFilter();
    		filter3.addAction(MY_BROADCAST_ACTION);
    		filter1.setPriority(6);
    		registerReceiver(thirdBroadCast, filter3);
    		
    		
    		
    //		finish();
    	}
     
    	
    	public void sendBroadCast(View v){
    		//这里创建电台来发送广播,需要一个intent就行了
    		Intent intent = new Intent();
    		//给广播设置一个action,方便广播接收者接收相应的广播
    		intent.setAction(MY_BROADCAST_ACTION);
    		intent.putExtra("data", "这里是来自自定义电台发送的广播");
    //		sendBroadcast(intent);//这里发送的是无序广播
    		
    		/*
    		 * 有序广播
    		 * intent:你要发送的数据,包含数据和动作
    		 * receiverPermission:权限,一般不用为null
    		 * resultReceiver:最终接收者
    		 * Handler:消息处理
    		 * initialCode:初始化编码1 - 1000
    		 * initialData:初始化的数据
    		 * initialExtras:额外的数据,一般不用
    		 */
    		sendOrderedBroadcast(intent, null, null, null, 1, "10000", null);
    		
    	}
    	
    	
    	//这个广播接收者可用写在任意的类中,甚至可用写在别的app中。也能接收到对应电台发送的广播,只要action对应
    	//这些广播可以通过在清单文件中注册,也可以手动的通过registerReceiver方法注册
    	class FirstBroadCast extends BroadcastReceiver{
     
    		@Override
    		public void onReceive(Context context, Intent intent) {
    			String action = intent.getAction();
    			if (MY_BROADCAST_ACTION.equals(action)) {
    				String data = intent.getStringExtra("data");
    				Toast.makeText(context,
    						"FirstBroadCast接收到广播了,接收的广播的数据是:" + data, 1).show();
    				System.out.println("FirstBroadCast接收到广播了,接收的广播的数据是:" + data);
    			}
    		}
    		
    	}
    	class TwiceBroadCast extends BroadcastReceiver{
    		
    		@Override
    		public void onReceive(Context context, Intent intent) {
    			String action = intent.getAction();
    			if (MY_BROADCAST_ACTION.equals(action)) {
    				String data = intent.getStringExtra("data");
    				Toast.makeText(context,
    						"TwiceBroadCast接收到广播了,接收的广播的数据是:" + data, 1).show();
    				System.out.println("TwiceBroadCast接收到广播了,接收的广播的数据是:" + data);
    			}
    		}
    		
    	}
    	class ThirdBroadCast extends BroadcastReceiver{
    		
    		@Override
    		public void onReceive(Context context, Intent intent) {
    			String action = intent.getAction();
    			if (MY_BROADCAST_ACTION.equals(action)) {
    				String data = intent.getStringExtra("data");
    				Toast.makeText(context,
    						"ThirdBroadCast接收到广播了,接收的广播的数据是:" + data, 1).show();
    				System.out.println("ThirdBroadCast接收到广播了,接收的广播的数据是:" + data);
    			}
    		}
    		
    	}
    	
    	
    	@Override
    	protected void onDestroy() {
    		super.onDestroy();
    		if(firstBroadCast != null){
    			unregisterReceiver(firstBroadCast);
    		}
    		if(twiceBroadCast != null){
    			unregisterReceiver(twiceBroadCast);
    		}
    		if(thirdBroadCast != null){
    			unregisterReceiver(thirdBroadCast);
    		}
    		
    	}
    	
    	
    }
    • 在代码中调用Context.registerReceiver()
    • 典型写法示例如下:
    public class MainActivity extends AppCompatActivity {
    
        public static final String BROADCAST_ACTION = "com.example.whd_alive";
        private BroadcastReceiver mBroadcastReceiver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //实例化MyBroadcastReceiver 
            mBroadcastReceiver = new MyBroadcastReceiver();
            //实例化IntentFilter
            IntentFilter intentFilter = new IntentFilter();
    
            //设置接收广播的类型
            intentFilter.addAction(BROADCAST_ACTION);
    
            //动态注册
            registerReceiver(mBroadcastReceiver, intentFilter);
        }
    
        //销毁广播
        //当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
        //当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(mBroadcastReceiver);
        }
    }
    

    实现流程

    1. 广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;
    2. 广播发送者通过binder机制向AMS发送广播;
    3. AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver
    4. AMS将广播发送到上述符合条件的BroadcastReceiver相应的消息循环队列中
    5. BroadcastReceiver通过消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

    四.不同注册方式的广播接收器回调onReceive(context, intent)中的context具体类型

    1).对于静态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是ReceiverRestrictedContext;

    2).对于全局广播的动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Activity Context;

    3).对于通过LocalBroadcastManager动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Application Context。

    注:对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。

    五、不同Android API版本中广播机制相关API重要变迁

    1).Android5.0/API level 21开始粘滞广播和有序粘滞广播过期,以后不再建议使用;

    2).”静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到,但此种描述自Android 3.1开始有可能不再成立“

    Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。

    FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)

    FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包

    主要原因如下:

    自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。

    详情参加Android官方文档:http://developer.android.com/about/versions/android-3.1.html#launchcontrols

    由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。

    但是对于自定义的广播,可以通过复写此flag为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。

    1 Intent intent = new Intent();
    2 intent.setAction(BROADCAST_ACTION);
    3 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
    4 intent.putExtra("name", "qqyumidi");
    5 sendBroadcast(intent);
    注1:对于动态注册类型的BroadcastReceiver,由于此注册和取消注册实在其他组件(如Activity)中进行,因此,不受此改变影响。
    注2:在3.1以前,相信不少app可能通过静态注册方式监听各种系统广播,以此进行一些业务上的处理(如即时app已经退出,仍然能接收到,可以启动service等..),3.1后,静态注册接受广播方式的改变,将直接导致此类方案不再可行。于是,通过将Service与App本身设置成不同的进程已经成为实现此类需求的可行替代方案。

    六、Android 广播的生命周期    

     一个广播接收者有一个回调方法:void onReceive(Context curContext, Intent broadcastMsg)。当一个广播消息到达接收者时,Android调用它的onReceive()方法并传递给它包含消息的Intent对象。广播接收者被认为仅当它执行这个方法时是活跃的。当onReceive()返回后,它是不活跃的。

    有一个活跃的广播接收者的进程是受保护的,不会被杀死。但是系统可以在任何时候杀死仅有不活跃组件的进程,当占用的内存别的进程需要时。

    这带来一个问题,当一个广播消息的响应时费时的,因此应该在独立的线程中做这些事,远离用户界面其它组件运行的主线程。如果onReceive()衍生线程然后返回,整个进程,包括新的线程,被判定为不活跃的(除非进程中的其它应用程序组件是活跃的),将使它处于被杀的危机。解决这个问题的方法是onReceive()启动一个服务,及时服务做这个工作,因此系统知道进程中有活跃的工作在做。

        Broadcast Receive为广播接收器,它和事件处理机制类似,只不过事件的处理机制是程序组件级别的,广播处理机制是系统级别的。

    Broadcast Receiver用于接收并处理广播通知(broadcast announcements)。多数的广播是系统发起的,如地域变换、电量不足、来电来信等。程序也可以播放一个广播。程序可以有任意数量的 broadcast receivers来响应它觉得重要的通知。broadcast receiver可以通过多种方式通知用户:启动activity、使用NotificationManager、开启背景灯、振动设备、播放声音等,最典型的是在状态栏显示一个图标,这样用户就可以点它打开看通知内容。

    通常我们的某个应用或系统本身在某些事件(电池电量不足、来电来短信)来临时会广播一个Intent出去,我们可以利用注册一个Broadcast Receiver来监听到这些Intent并获取Intent中的数据。

    七、开发BroadcastReceiver的一些注意事项:

    BroadcastReceiver的生命周期比较短,一些比较费时的操作不应该放在onReceiver里完成。如果在onReceiver()的方法不能在10秒内执行完成,将会产生程序无响应也就是我们熟悉的ANR(Application not Response)。但是如果非得要在这里面执行一些费时的操作我们可以在这个onReceiver去启动一个Service来完成这样的一个费时操作。

    广播接收者的对象只有在回调onReceive()这个函数时有效,一旦从这个函数返回,这个对象就被结束,不再激活。在onReceive()中,任何异步的操作都是不可行的。因为需要从onRecive()这个函数回来去处理异步的操作,但是这个广播接收者不再被激活,系统将会在异步操作完成前结束进程。特别是在这里面显示对话框或者绑定service不行,但是可以用其他替代的方式,前者可以notificationManger,后者用startService()发送请求。

    下边是一个如何使用广播的代码案例地址,需要的可以下载:

    http://download.csdn.net/detail/oonullpointeralex/9064049

    八、系统广播清单


    android.accounts.LOGIN_ACCOUNTS_CHANGED 
    android.accounts.action.ACCOUNT_REMOVED 
    android.app.action.ACTION_PASSWORD_CHANGED 
    android.app.action.ACTION_PASSWORD_EXPIRING 
    android.app.action.ACTION_PASSWORD_FAILED 
    android.app.action.ACTION_PASSWORD_SUCCEEDED 
    android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED 
    android.app.action.APP_BLOCK_STATE_CHANGED 
    android.app.action.DEVICE_ADMIN_DISABLED 
    android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED 
    android.app.action.DEVICE_ADMIN_ENABLED 
    android.app.action.DEVICE_OWNER_CHANGED 
    android.app.action.INTERRUPTION_FILTER_CHANGED 
    android.app.action.LOCK_TASK_ENTERING 
    android.app.action.LOCK_TASK_EXITING 
    android.app.action.NEXT_ALARM_CLOCK_CHANGED 
    android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED 
    android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED 
    android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED 
    android.app.action.NOTIFICATION_POLICY_CHANGED 
    android.app.action.PROFILE_OWNER_CHANGED 
    android.app.action.PROFILE_PROVISIONING_COMPLETE 
    android.app.action.SYSTEM_UPDATE_POLICY_CHANGED 
    android.appwidget.action.APPWIDGET_DELETED 
    android.appwidget.action.APPWIDGET_DISABLED 
    android.appwidget.action.APPWIDGET_ENABLED 
    android.appwidget.action.APPWIDGET_HOST_RESTORED 
    android.appwidget.action.APPWIDGET_RESTORED 
    android.appwidget.action.APPWIDGET_UPDATE 
    android.appwidget.action.APPWIDGET_UPDATE_OPTIONS 
    android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED 
    android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.adapter.action.DISCOVERY_FINISHED 
    android.bluetooth.adapter.action.DISCOVERY_STARTED 
    android.bluetooth.adapter.action.LOCAL_NAME_CHANGED 
    android.bluetooth.adapter.action.SCAN_MODE_CHANGED 
    android.bluetooth.adapter.action.STATE_CHANGED 
    android.bluetooth.device.action.ACL_CONNECTED 
    android.bluetooth.device.action.ACL_DISCONNECTED 
    android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED 
    android.bluetooth.device.action.BOND_STATE_CHANGED 
    android.bluetooth.device.action.CLASS_CHANGED 
    android.bluetooth.device.action.FOUND 
    android.bluetooth.device.action.NAME_CHANGED 
    android.bluetooth.device.action.PAIRING_REQUEST 
    android.bluetooth.device.action.UUID 
    android.bluetooth.devicepicker.action.DEVICE_SELECTED 
    android.bluetooth.devicepicker.action.LAUNCH 
    android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT 
    android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED 
    android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED 
    android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED 
    android.content.pm.action.SESSION_COMMITTED 
    android.hardware.action.NEW_PICTURE 
    android.hardware.action.NEW_VIDEO 
    android.hardware.hdmi.action.OSD_MESSAGE 
    android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS 
    android.hardware.usb.action.USB_ACCESSORY_ATTACHED 
    android.hardware.usb.action.USB_ACCESSORY_DETACHED 
    android.hardware.usb.action.USB_DEVICE_ATTACHED 
    android.hardware.usb.action.USB_DEVICE_DETACHED 
    android.intent.action.ACTION_POWER_CONNECTED 
    android.intent.action.ACTION_POWER_DISCONNECTED 
    android.intent.action.ACTION_SHUTDOWN 
    android.intent.action.AIRPLANE_MODE 
    android.intent.action.APPLICATION_RESTRICTIONS_CHANGED 
    android.intent.action.BATTERY_CHANGED 
    android.intent.action.BATTERY_LOW 
    android.intent.action.BATTERY_OKAY 
    android.intent.action.BOOT_COMPLETED 
    android.intent.action.CAMERA_BUTTON 
    android.intent.action.CLOSE_SYSTEM_DIALOGS 
    android.intent.action.CONFIGURATION_CHANGED 
    android.intent.action.CONTENT_CHANGED 
    android.intent.action.DATA_SMS_RECEIVED 
    android.intent.action.DATE_CHANGED 
    android.intent.action.DEVICE_STORAGE_LOW 
    android.intent.action.DEVICE_STORAGE_OK 
    android.intent.action.DOCK_EVENT 
    android.intent.action.DOWNLOAD_COMPLETE 
    android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED 
    android.intent.action.DREAMING_STARTED 
    android.intent.action.DREAMING_STOPPED 
    android.intent.action.DROPBOX_ENTRY_ADDED 
    android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE 
    android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE 
    android.intent.action.FACTORY_RESET 
    android.intent.action.FETCH_VOICEMAIL 
    android.intent.action.GTALK_CONNECTED 
    android.intent.action.GTALK_DISCONNECTED 
    android.intent.action.HEADSET_PLUG 
    android.intent.action.HEADSET_PLUG 
    android.intent.action.INPUT_METHOD_CHANGED 
    android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION 
    android.intent.action.LOCALE_CHANGED 
    android.intent.action.LOCKED_BOOT_COMPLETED 
    android.intent.action.MANAGE_PACKAGE_STORAGE 
    android.intent.action.MASTER_CLEAR_NOTIFICATION 
    android.intent.action.MEDIA_BAD_REMOVAL 
    android.intent.action.MEDIA_BUTTON 
    android.intent.action.MEDIA_CHECKING 
    android.intent.action.MEDIA_EJECT 
    android.intent.action.MEDIA_MOUNTED 
    android.intent.action.MEDIA_NOFS 
    android.intent.action.MEDIA_REMOVED 
    android.intent.action.MEDIA_SCANNER_FINISHED 
    android.intent.action.MEDIA_SCANNER_SCAN_FILE 
    android.intent.action.MEDIA_SCANNER_STARTED 
    android.intent.action.MEDIA_SHARED 
    android.intent.action.MEDIA_UNMOUNTABLE 
    android.intent.action.MEDIA_UNMOUNTED 
    android.intent.action.MY_PACKAGE_REPLACED 
    android.intent.action.NEW_OUTGOING_CALL 
    android.intent.action.NEW_VOICEMAIL 
    android.intent.action.PACKAGES_SUSPENDED 
    android.intent.action.PACKAGES_UNSUSPENDED 
    android.intent.action.PACKAGE_ADDED 
    android.intent.action.PACKAGE_CHANGED 
    android.intent.action.PACKAGE_DATA_CLEARED 
    android.intent.action.PACKAGE_FIRST_LAUNCH 
    android.intent.action.PACKAGE_FULLY_REMOVED 
    android.intent.action.PACKAGE_INSTALL 
    android.intent.action.PACKAGE_NEEDS_VERIFICATION 
    android.intent.action.PACKAGE_REMOVED 
    android.intent.action.PACKAGE_REPLACED 
    android.intent.action.PACKAGE_RESTARTED 
    android.intent.action.PACKAGE_VERIFIED 
    android.intent.action.PHONE_STATE 
    android.intent.action.PROVIDER_CHANGED 
    android.intent.action.PROXY_CHANGE 
    android.intent.action.QUERY_PACKAGE_RESTART 
    android.intent.action.REBOOT 
    android.intent.action.SCREEN_OFF 
    android.intent.action.SCREEN_ON 
    android.intent.action.SIM_STATE_CHANGED 
    android.intent.action.TIMEZONE_CHANGED 
    android.intent.action.TIME_SET 
    android.intent.action.TIME_TICK 
    android.intent.action.UID_REMOVED 
    android.intent.action.UMS_CONNECTED 
    android.intent.action.UMS_DISCONNECTED 
    android.intent.action.USER_PRESENT 
    android.intent.action.USER_UNLOCKED 
    android.intent.action.WALLPAPER_CHANGED 
    android.media.ACTION_SCO_AUDIO_STATE_UPDATED 
    android.media.AUDIO_BECOMING_NOISY 
    android.media.RINGER_MODE_CHANGED 
    android.media.SCO_AUDIO_STATE_CHANGED 
    android.media.VIBRATE_SETTING_CHANGED 
    android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION 
    android.media.action.HDMI_AUDIO_PLUG 
    android.media.action.MICROPHONE_MUTE_CHANGED 
    android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION 
    android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED 
    android.media.tv.action.INITIALIZE_PROGRAMS 
    android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT 
    android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED 
    android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED 
    android.net.conn.BACKGROUND_DATA_SETTING_CHANGED 
    android.net.conn.CONNECTIVITY_CHANGE 
    android.net.conn.RESTRICT_BACKGROUND_CHANGED 
    android.net.nsd.STATE_CHANGED 
    android.net.scoring.SCORER_CHANGED 
    android.net.scoring.SCORE_NETWORKS 
    android.net.wifi.NETWORK_IDS_CHANGED 
    android.net.wifi.RSSI_CHANGED 
    android.net.wifi.SCAN_RESULTS 
    android.net.wifi.STATE_CHANGE 
    android.net.wifi.WIFI_STATE_CHANGED 
    android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED 
    android.net.wifi.p2p.CONNECTION_STATE_CHANGE 
    android.net.wifi.p2p.DISCOVERY_STATE_CHANGE 
    android.net.wifi.p2p.PEERS_CHANGED 
    android.net.wifi.p2p.STATE_CHANGED 
    android.net.wifi.p2p.THIS_DEVICE_CHANGED 
    android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED 
    android.net.wifi.supplicant.CONNECTION_CHANGE 
    android.net.wifi.supplicant.STATE_CHANGE 
    android.nfc.action.ADAPTER_STATE_CHANGED 
    android.nfc.action.TRANSACTION_DETECTED 
    android.os.action.DEVICE_IDLE_MODE_CHANGED 
    android.os.action.POWER_SAVE_MODE_CHANGED 
    android.provider.Telephony.SECRET_CODE 
    android.provider.Telephony.SIM_FULL 
    android.provider.Telephony.SMS_CB_RECEIVED 
    android.provider.Telephony.SMS_DELIVER 
    android.provider.Telephony.SMS_RECEIVED 
    android.provider.Telephony.SMS_REJECTED 
    android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED 
    android.provider.Telephony.WAP_PUSH_DELIVER 
    android.provider.Telephony.WAP_PUSH_RECEIVED 
    android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED 
    android.provider.action.EXTERNAL_PROVIDER_CHANGE 
    android.provider.action.SYNC_VOICEMAIL 
    android.security.STORAGE_CHANGED 
    android.security.action.KEYCHAIN_CHANGED 
    android.security.action.KEY_ACCESS_CHANGED 
    android.security.action.TRUST_STORE_CHANGED 
    android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED 
    android.speech.tts.engine.TTS_DATA_INSTALLED 
    android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED 
    android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED 
    android.telephony.action.REFRESH_SUBSCRIPTION_PLANS 
    android.telephony.action.SIM_APPLICATION_STATE_CHANGED 
    android.telephony.action.SIM_CARD_STATE_CHANGED 
    android.telephony.action.SIM_SLOT_STATUS_CHANGED 
    android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED 
    android.telephony.euicc.action.NOTIFY_CARRIER_SETUP 
    android.telephony.euicc.action.OTA_STATUS_CHANGED

  • 相关阅读:
    Big Event in HDU
    ACM STEPS——Chapter Two——Section One
    黑马day15 文件上传&amp;apche的工具包
    阿里云部署Docker(8)----安装和使用redmine
    【React Native开发】React Native控件之ProgressBarAndroid进度条解说(12)
    python抓取新浪微博评论并分析
    使用Xcode-debug模式和release模式
    hdu 5417 Victor and Machine
    《Head First 设计模式》学习笔记——适配器模式 + 外观模式
    设计模式(二)
  • 原文地址:https://www.cnblogs.com/journeyzc/p/12574375.html
Copyright © 2020-2023  润新知