一、广播
广播接受者用来接收广播Intent的。广播Intent的发送是通过调用sendBroadcast/sendOrderedBroadcasr来实现的。通常一个广播Intent可以被订阅次Intent的多个广播接受者所接收。
1.1、广播特点
2.3:第一次安装不管有没有页面或在设置页面强行停止,广播接受者都生效。
4.0:安全升级后,广播接受者第一次安装必须有界面,设置页面如果强行停止,广播不再生效。
广播中开启activity:
Intent intent=new Intent(context,main.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);
1.3、生命周期
广播生命周期只有十秒左右,如果在onReceive()内做超过十秒内的事情,就会报错。
每次广播到来时,会重新创建 BroadcastReceiver对象,并且调用 onReceive()方法,执行完以后,该对象即被销毁.当onReceive()方法在10 秒内没有执行完毕
,Android会认为该程序无响应.所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。
1.4、自定义广播
1.无序广播
a) 无序广播不可以被拦截,如果被拦截则报错
b) 所有接受无序广播的广播接收者在此广播发送时均能接受到此广播。
c) 无序广播是通过sendBroadcast方法进行发送。
// 创建意图 Intent intent = new Intent(); // 设置Action intent.setAction("cn.legend.broadcast"); // 绑定数据 intent.putExtra("data","我是无序广播数据"); // 发送无序广播 sendBroadcast(intent);
2.有序广播
a)有序广播可以被拦截,且优先级高的接受者可以拦截优先级低的。
b)广播接收者的优先级取值范围:-1000(最低)--1000(最高)。
c)相同优先级下,接收的顺序要看清单文件声明顺序,谁先声明谁先收到广播。
d)无序广播使用sendOrderedBroadcasr方法发送,使用abortBroadcast方法拦截。
e)广播接收者的优先级在清单文件中声明:<intent-filter>标签下设置"android:property"属性设置。
Intent intent = new Intent(); intent.setAction("cn.legend.data"); /** * 参数1:意图,广播,所有匹配的这一意图将接收机接收广播。 * 参数2:receiverPermission 这是权限,一个接收器必须持以接收您的广播。如果为 null,不经许可的要求。 * 参数3:BroadcastReceiver类型,自己定义的接收器作为最终接收器 * 参数4:Handle类型,用于执行接收器的回调,如果为null则在主线程中执行 * 参数5:initialCode 一种结果代码的初始值。通常为 Activity.RESULT_OK 。这个值是 -1 ; * 参数6:initialData 一种结果数据的初始值。通常情况下为空 , 是 String 类型 ; * 参数7:Bundle类型,额外的数据 */ sendOrderedBroadcast(intent,null,null,null,RESULT_OK,"一万元",null);
3.粘性广播
Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制。在发送完广播后才被注册的广播接收者无法接收到在注册前发送的广播,但是可以接收到注册前发送的sticky broadcast(粘性广播)。
Intent intent = new Intent(); intent.setAction("cn.legend.data"); sendStickyBroadcast(intent);
下面看一个粘性广播的实例:
需求:发送一个粘性广播,并在5秒后开启一个Activity,在新开启的Activity中注册广播接受者来接收到广播。
a) 发送一个粘性广播,5秒后打开SecondActivity:
public class MainActivity extends Activity { private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sendStickBroadcastMethod(); // 五秒后开启Activity Message startMessage = Message.obtain(); mHandler.sendMessageDelayed(startMessage, 5 * 1000); } /** * 发送粘性广播的方法 */ private void sendStickBroadcastMethod() { Intent intent = new Intent(); intent.setAction("cn.legend.stick"); intent.putExtra("time", String.valueOf(System.currentTimeMillis())); sendStickyBroadcast(intent); } }
b) SecondActivity中注册广播接受者来接收到广播:
public class SecondActivity extends Activity { private MyBroadCastReceiver mReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mReceiver = new MyBroadCastReceiver(); IntentFilter intentFilter=new IntentFilter(); intentFilter.addAction("cn.legend.stick"); registerReceiver(mReceiver, intentFilter); } /** * 广播接受者 */ private class MyBroadCastReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String time = intent.getStringExtra("time"); System.out.println("收到发送的时间:" + time); System.out.println("当前的系统时间:" + System.currentTimeMillis()); } } @Override protected void onDestroy() { super.onDestroy(); if(mReceiver != null){ unregisterReceiver(mReceiver); } } }
c) 最后不要忘记在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
4.本地广播
前面所介绍的广播都属于系统全局广播,广播可以被任何应用所接收到,这样就导致安全问题。本地广播只能在应用程序的内部进行传递,更加安全和高效。
public class MainActivity extends Activity { private LocalBroadcastManager mManager; private LocalRecerver mLocalRecerver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.btn); mManager = LocalBroadcastManager.getInstance(this); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 发送本地广播 Intent intent = new Intent("cn.legend.local.LOCAL_BROADCAST"); mManager.sendBroadcast(intent); } }); // 注册广播监听器 IntentFilter filter = new IntentFilter(); filter.addAction("cn.legend.local.LOCAL_BROADCAST"); mLocalRecerver = new LocalRecerver(); mManager.registerReceiver(mLocalRecerver, filter); } // 注册本地广播接收器 class LocalRecerver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show(); } } }
注意:本地广播只能采用动态注册,因为静态注册主要是为了让程序在未启动的情况下也能收到广播,而发送本地广播时我们的程序已经启动了。
1.5、广播注册
1.静态注册
静态注册是直接在清单文件中进行配置
<receiver android:name="cn.legend.regist.ScreenReceiver"> <intent-filter > <action android:name="android.intent.action.SCREEN_OFF"/> <action android:name="android.intent.action.SCREEN_ON"/> </intent-filter> </receiver>
2.动态注册
在Activity中进行动态注册时,在Activity销毁的时候一定要取消注册,否则会内存泄露。
public class MainActivity extends Activity { private ScreenReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建自定义的广播接收对象的实例 receiver = new ScreenReceiver(); //创建过滤器的类 IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.SCREEN_OFF"); filter.addAction("android.intent.action.SCREEN_ON"); //动态注册 registerReceiver(receiver, filter); } @Override protected void onDestroy() { //取消注册 unregisterReceiver(receiver); super.onDestroy(); } }
1.6、系统广播
1.监听SD卡
a) 创建一个SdcardStateReceiver的类继承BroadcastReceiver,创建广播需要在清单文件中先进行注册,而监测SD卡还需要配置action和data属性
<receiver android:name="cn.legend.listensdcard.SdcardStateReceiver" > <!-- 指定内存卡被挂载和卸载的动作 --> <intent-filter> <action android:name="android.intent.action.MEDIA_MOUNTED" /> <action android:name="android.intent.action.MEDIA_UNMOUNTED" /> <data android:scheme="file" /> </intent-filter> </receiver>
b) 在SdcardStateReceiver类中写下如下代码:
public class SdcardStateReceiver extends BroadcastReceiver { //接受注册广播的时候调用 @Override public void onReceive(Context context, Intent intent) { //获取广播的事件 String action = intent.getAction(); //判断获取到的事件 if("android.intent.action.MEDIA_MOUNTED".equals(action)){ //弹出土司提示 Toast.makeText(context, "Sd卡被挂载的了....", 0).show(); }else if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){ Toast.makeText(context, "Sd卡被卸载的了....", 0).show(); } } }
2.监听来电
a) 在MainActivity中获取安全中心的号码,保存到配置文件中:
String phone = et_phone.getText().toString().trim(); if(TextUtils.isEmpty(phone)){ Toast.makeText(this, "号码不能为空", 0).show(); return; } sp.edit().putString("phone", phone).commit(); Toast.makeText(getApplicationContext(), "保存成功", 0).show();
b) 创建广播类OutGoingCallReceiver,在清单文件中声明:
<receiver android:name="cn.legend.caller.OutGoingCallReceiver"> <intent-filter > <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> </intent-filter> </receiver>
c) 在OutGoingCallReceiver中拼接安全号+电话号码,当拨打电话是0开头的长途电话,则添加安全中心号码:
public class OutGoingCallReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //监听获取当前拨打的电话 String phone = getResultData(); //从配置文件取出要拼接的区号 SharedPreferences sp = context.getSharedPreferences("config", 0); String number = sp.getString("phone", ""); //判断号码是否以0开头,如果是则说明是长途,就带上区号 if(phone.startsWith("0")){ setResultData(number+phone); } } }
注:需要在清单文件中添加权限:android.permission.PROCESS_OUTGOING_CALLS
3.监听短信
a) 创建一个广播类SmsReceiver用来监听和拦截短信:
public class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //通过短信获取信息,返回值需要手动改成Object[]数组 Object[] objects = (Object[]) intent.getExtras().get("pdus"); for (Object object : objects) { SmsMessage message = SmsMessage.createFromPdu((byte[])object); String body = message.getMessageBody(); String address = message.getOriginatingAddress(); System.out.println("bdoy:"+body+",address:"+address); } } }
b) 清单文件配置:
<receiver android:name="cn.legend.sms.SmsReceiver" > <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
注:拦截短信需要在清单文件配置权限:android.permission.RECEIVE_SMS
4.监听安装
a) 创建广播类AppStateReceiver,在清单文件中配置,不需要配置权限:
<receiver android:name="cn.legend.listen.AppStateReceiver" > <intent-filter> <!-- 监听程序安装和卸载 --> <action android:name="android.intent.action.PACKAGE_ADDED" /> <action android:name="android.intent.action.PACKAGE_REMOVED" /> <data android:scheme="package" /> </intent-filter> </receiver>
b) 在AppStateReceiver中写下如下代码进行监听
public class AppStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //判断是安装还是卸载 if("android.intent.action.PACKAGE_ADDED".equals(action)){ System.out.println("应用程序被安装了..."); }else if("android.intent.action.PACKAGE_REMOVED".equals(action)) { System.out.println("应用程序被卸载了..."); } } }
5.监听开机
a) 创建广播类BootReceiver,清单文件做如下配置,不需要权限:
<receiver android:name="cn.legend.reboot.BootReceiver" > <intent-filter> <!-- 开机自动启动 --> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
b) 在BootReceiver中使用广播开启activity
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("手机已经启动");
//在广播中开启一个activity Intent intent2 = new Intent(context, MainActivity.class); //由任务栈来开启 intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent2); } }
##############################################