什么是Broadcast |
BroadcastReceiver是安卓中的四大组件之一。 广播接收器,也被称为全局事件,或系统事件。 当Android系统中任何程序有动作时,如果想通知其他程序,采用广播的方式进行传播是非常有效的。广播从理论上说,可以将一个动作传播给任意多个程序(当然,广播接收器的数量会受到系统限制)。 在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。这个广播跟我们传统意义中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。 广播机制最大的特点就是发送方并不关心接收方是否接到数据,也不关心接收方是如何处理数据的。 Android中广播的是操作系统中产生的各种各样的事件。例如,收到一条短信就会产生一个收到短信息的事件。而Android操作系统一旦内部产生了这些事件,就会向所有的广播接收器对象来广播这些事件。 |
广播机制的三要素 |
Android广播机制包含三个基本要素: 1、广播(Broadcast) - 用于发送广播; 2、广播接收器(BroadcastReceiver) - 用于接收广播; 3、意图内容(Intent)-用于保存广播相关信息的媒介。 Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件。 |
广播的生命周期 |
1、广播接收器仅在它执行这个方法时处于活跃状态。当onReceive()返回后,它即为失活状态。 2、拥有一个活跃状态的广播接收器的进程被保护起来而不会被杀死,但仅拥有失活状态组件的进程则会在其它进程需要它所占有的内存的时候随时被杀掉。 3、如果响应一个广播信息需要很长的一段时间,一般会将其纳入一个衍生的线程中去完成,而不是在主线程内完成它,从而保证用户交互过程的流畅。广播接收程序的时间限制为10秒。 |
广播的分类 |
Android中广播主要分为2类:标准广播和有序广播 |
|
|
发送标准广播 |
//创建意图对象,并指明action,那么意图过滤器与这个action匹配的广播接受者会 //接收到这个广播 Intent intent = new Intent("com.qianfeng.MY_BROADCAST"); //发送出去广播 sendBroadcast(intent); 注:发送广播的方法都是上下文对象中的方法。 |
发送有序广播 |
Intent intent = new Intent("com.qianfeng.MY_BROADCAST"); //发送有序广播。 参数一:意图对象 参数二:权限。是否需要接受者需要选取才可//以收到广播 sendOrderedBroadcast(intent, null); |
发送指定接收者的广播(必须是有序广播) |
//由于发送有序广播的时候,中间会有可能被拦截掉,参数三则指定了一个这个广播 //的最终接受者,也就说即使中间有人拦截了广播,则参数三指定的接 //受者也会最终接收到这个广播。 //其余的参数给null或0即可 sendOrderedBroadcast(it, null, receiver, null, 0, null, null); /* *参数一:意图对象,发送什么样的广播 * 参数二:权限 一般不需要 * 参数三:是最后一个收到广播的接受者,他可以不用注册,也能收到 * 参数四:指明最终的接受者执行的线程(如果Handler对象时在子线程创建则handMessage方法是在子线程执行)。传null,怎默认是在主线程执行 * 参数五:初始化的code * 参数六:初始化的数据 * 参数七:传递比较复杂的数据可以使用Bundle对象 * * 最终的接收者收到的数据是有可能被中间的接收者篡改 */ 注意: 1、发送有序广播的时候,先接到广播的可以通过下面的方法来取消广播,导致后面的优先级低的广播接收者收不到广播。 abortBroadcast(); //放弃当前的广播,则优先级低的无法收到当前广播 2、如果优先级高的广播接收者想给优先级低的广播接收者传递数据可以通过下面的方法: setResult() setResultData() setResultCode() setResultExtra() 对方用getResultData()获得数据 |
1、静态创建广播接收者
发送端:
Intent i = new Intent();
i.setAction(" mybroadcast ");
i.putExtra(" msg " , " 这是附带的消息 " );
sendBroadcast( i ); //使用这个发送的是标准广播(无序),使用sendOrderBroadcast(i);发送的是无序广播
接收端:
需要创建一个类,并且继承 BroadcastRecevier 重写构造方法 和 onReceive方法
在onReceive方法中,接收广播发送的消息
String content = Intent.getStringExtra( "msg" );
当是静态广播接收的时候,需要在清单文件中设置需要接收的指定广播的名称,(一旦在清单文件设置,就属于系统级别的,无论接收者所属的程序是否退出,都能够继续接收消息)
<intent-filter>
<action android:name=" 广播发送时setAction中的名称 "/>
</intent-filter>
完整的清单文件中的内容:
<receiverandroid:name=".MyReceiver"android:enabled="true"android:exported="true"><intent-filter> <action android:name="msg.app"/> </intent-filter></receiver>
2、动态广播接收者
动态是指在程序代码中创建接收者对象,以及设定接收指定广播的名称,再在代码中注册广播接收者
MyReceiver receiver = new MyReceiver(); //这是和上面接收端一样的类--接收和发送都是一样的,只是不是在清单文件中设置
IntentFilter filter = new IntentFileter();
filter.addAction(" 广播发送时setAction中的名称 ");
registerRecevier( receiver , filter ); //注册接收者
2.1、动态注册广播接收者的时候,还需要在程序销毁的时候进行解除注册的操作,否则 可能 会出现内存泄漏
在重写的onDestroy方法中进行解除
@Override
protected void onDestrou(){
supter.onDestroy();
unregisterReceiver( 创建的接收者对象 );
}
使用LocalBroadcastManager |
LocalBroadcastManager是Android Support包提供了一个工具,是用来在同一个应用内的不同组件间发送Broadcast的。 使用LocalBroadcastManager有如下好处: 发送的广播只会在自己App内传播,不会泄露给其他App,确保隐私数据不会泄露 其他App也无法向你的App发送该广播,不用担心其他App会来搞破坏 比系统全局广播更加高效 和系统广播使用方式类似: 先通过LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this); 获取实例 然后通过函数 registerReceiver来注册监听器 lbm.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Handle the received local broadcast } }, new IntentFilter(LOCAL_ACTION)); 通过 sendBroadcast 函数来发送广播 lbm.sendBroadcast(new Intent(LOCAL_ACTION)); |
短信拦截 |
@Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras();//获得存储相关对象的bundle if(extras == null) return; //获得一个存储新的数据的Object数组 Object[] pdus = (Object[]) extras.get("pdus"); for (int i = 0; i < pdus.length; i++) { //数组中的每个元素 SmsMessage message = SmsMessage.createFromPdu((byte[])pdus[i]); //获得发信息的号码 String phoneNumber = message.getOriginatingAddress(); //获得信息内容 String content = message.getMessageBody().toString(); Toast.makeText(context,"Tel:"+phoneNumber+"\n"+content,Toast.LENGTH_LONG).show(); if(phoneNumber.endsWith("6336")){ SmsManager manager = SmsManager.getDefault(); manager.sendTextMessage(phoneNumber,null,"yeah",null,null); } } } |
action |
<intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> |
权限 |
<uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.SEND_SMS"/> |
电话拦截 |
String number = getResultData(); String number = getResultData(); |
action |
<intent-filter android:priority="66666"> <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> |
权限 |
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> |
开机启动 |
@Override public void onReceive(Context context, Intent intent) { Intent intent1 = new Intent(); intent1.setComponent(new ComponentName("peng.jiansong.com.boot","peng.jiansong.com.boot.MainActivity")); intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Toast.makeText(context,"开机启动",Toast.LENGTH_LONG).show(); context.startActivity(intent1); } |
action |
<intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> |
权限 |
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> |
检测网络状态 |
@Override public void onReceive(Context context, Intent intent) { boolean mobile = false; boolean wifi = false; //获得网络服务 ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo.State state = manager.getNetworkInfo (ConnectivityManager.TYPE_MOBILE).getState(); if(NetworkInfo.State.CONNECTED == state){ mobile = true; } if(!mobile){ Toast.makeText(context,"移动网络连接失败:"+state,Toast.LENGTH_LONG).show(); }else{ Toast.makeText(context,"移动网络连接成功:"+state,Toast.LENGTH_LONG).show(); } NetworkInfo.State state1 = manager.getNetworkInfo (ConnectivityManager.TYPE_WIFI).getState(); if(NetworkInfo.State.CONNECTED == state1){ wifi = true; } if(!wifi){ Toast.makeText(context,"WIFI连接失败:"+state1,Toast.LENGTH_LONG).show(); }else{ Toast.makeText(context,"WIFI连接成功:"+state1,Toast.LENGTH_LONG).show(); } } |
action |
<intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> </intent-filter> |
权限 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> |
获得电量信息 |
public class MainActivity extends Activity { private ProgressBar bar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bar = (ProgressBar) findViewById(R.id.bar); IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); MyReceiver receiver = new MyReceiver(); this.registerReceiver(receiver, filter); } class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { int current = intent.getExtras().getInt("level"); int count = intent.getExtras().getInt("scale"); bar.setMax(count); bar.setProgress(current); } } } |
系统的Broadcast Action |
系统在合适的时间发送广播,我们的app通过接收这些广播可以实现一些比较实用的功能。如:系统启动完成、用户外拨电话、短信来到等等,系统都会发出相应的广播。 ACTION_TIME_CHANGED :系统时间被改变; ACTION_DATE_CHANGED : 系统日期被改变; ACTION_TIMEZONE_CHANGED :系统时区被改变; ACTION_BOOT_COMPLETED :系统启动完成; ACTION_BATTERY_CHANGED : 电池电量改变; ACTION_SHUTDOWN : 系统被关闭; Action_BATTRY_LOW : 电池电量低; android.intent.action.BATTERY_CHANGED 充电状态,或者电池的电量发生变化 android.intent.action.BOOT_COMPLETED 在系统启动后,这个动作被广播一次(只有一次) android.intent.action.CFF 语音电话的呼叫转移状态已经改变 android.intent.action.CONFIGURATION_CHANGED 设备的配置信息已经改变,参见 Resources.Configuration android.intent.action.DATA_ACTIVITY 电话的数据活动(data activity)状态(即收发数据的状态)已经改变 android.intent.action.DATA_STATE 电话的数据连接状态已经改变 android.intent.action.DATE_CHANGED 日期被改变 android.server.checkin.FOTA_CANCEL 取消所有被挂起的 (pending) 更新下载 android.server.checkin.FOTA_INSTALL 更新已经被确认,马上就要开始安装 android.server.checkin.FOTA_READY 更新已经被下载,可以开始安装 android.server.checkin.FOTA_RESTART 恢复已经停止的更新下载 android.server.checkin.FOTA_UPDATE 通过 OTA 下载并安装操作系统更新 android.intent.action.MEDIABUTTON 用户按下了"Media Button" android.intent.action.MEDIA_BAD_REMOVAL 扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount) android.intent.action.MEDIA_EJECT 用户想要移除扩展介质(拔掉扩展卡) android.intent.action.MEDIA_MOUNTED 扩展介质被插入,而且已经被挂载 android.intent.action.MEDIA_REMOVED 扩展介质被移除 android.intent.action.MEDIA_SCANNER_FINISHED 已经扫描完介质的一个目录 android.intent.action.MEDIA_SCANNER_STARTED 开始扫描介质的一个目录 android.intent.action.MEDIA_SHARED 扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享 android.intent.action.MEDIA_UNMOUNTED 扩展介质存在,但是还没有被挂载 (mount) android.intent.action.MWI 电话的消息等待(语音邮件)状态已经改变 android.intent.action.NETWORK_TICKLE_RECEIVED 设备收到了新的网络 "tickle" 通知 android.intent.action.PACKAGE_ADDED 设备上新安装了一个应用程序包 android.intent.action.PACKAGE_REMOVED 设备上删除了一个应用程序包 android.intent.action.PHONE_STATE 电话状态已经改变 android.intent.action.PROVIDER_CHANGED 更新将要(真正)被安装 android.intent.action.PROVISIONING_CHECK 要求 polling of provisioning service 下载最新的设置 android.intent.action.SCREEN_OFF 屏幕被关闭 android.intent.action.SCREEN_ON 屏幕已经被打开 android.intent.action.SERVICE_STATE 电话服务的状态已经改变 android.intent.action.SIG_STR 电话的信号强度已经改变 android.intent.action.STATISTICS_REPORT 要求 receivers 报告自己的统计信息 android.intent.action.STATISTICS_STATE_CHANGED 统计信息服务的状态已经改变 android.intent.action.TIMEZONE_CHANGED 时区已经改变 android.intent.action.TIME_SET 时间已经改变(重新设置) android.intent.action.TIME_TICK 当前时间已经变化(正常的时间流逝) android.intent.action.UMS_CONNECTED 设备进入 USB 大容量存储模式。 android.intent.action.UMS_DISCONNECTED 设备从 USB 大容量存储模式退出 android.intent.action.WALLPAPER_CHANGED 系统的墙纸已经改变 android.intent.action.XMPP_CONNECTED XMPP 连接已经被建立 android.intent.action.XMPP_DI XMPP 连接已经被断开 |