BroadCastReceiver
来源:互联网 发布:社交媒体 大数据 编辑:程序博客网 时间:2024/05/16 10:48
BroadCastReceiver组件
- 广播的发送与接收
- 自定义权限广播
- 特殊的广播与接收者
- Android系统常见的广播事件
- 电话拦截的实现,拓展内容,涉及反射底层源代码
- 广播的其他特点
01-广播的发送与接收
无序广播特点:无序广播不可以被拦截,数据不能够修改,sendBroadCast(Intent)
普通广播是完全异步(就是不会被某个广播接收者终止)的,可以在同一时刻(逻辑上)被所有接收者接收到(其实被接收者接收到也是由顺序的,接收者配置的优先级越高,越先接收到,也就是说广播接收者的优先级对于无序广播也是有用的),消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播的传播。
有序广播特点:有序广播可以被拦截
abortBroadcast()
,数据可以被修改,sendOrderedBroadCast(Intent)有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A 接收者的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。在传递的过程中如果有某个接收者终止(abortBroadCast)了该广播,那么后面的接收者就接收不到该广播。
public class MainActivity extends Activity {private Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(new Runnable() { @Override public void run() { Looper.prepare(); handler = new Handler(); Looper.loop(); } }).start();}// 发送自定义的无序广播public void sendNormal(View view) { Intent intent = new Intent(); intent.setAction("com.itheima.mybroadcast.action"); intent.putExtra("data", "这是我给你发送的数据"); // 发送广播(无序) sendBroadcast(intent);}// 发送自定义的有序广播public void sendOrder(View view) { Intent intent = new Intent(); intent.setAction("com.itheima.orderedbroadcast.sendmoney"); /* * intent虽然可以携带数据,但是当前我们的业务需求上,让携带的数据可以被广播接收者修改.因此数据不能放到intent里面. */ // intent.putExtra("money", "1w"); /* * 参数1:intent 参数2:广播接收者应该具备的权限,如果不需要写null * 参数3:最终广播接收者,是有序广播接收者中永远都是最后一个执行的. * 参数4:handler对象,决定第三个参数(BroadCastReceiver中)onReceive()方法在哪个线程中执行, * 如果该handler是在主线程中创建的,那么参数3中的方法就在主线程中调用,如果为null,默认在主线程中. * 参数5/6/7:发送有序广播时,携带的初始化数据.之所有有三个,第一个是int[类型,第二个是String,第三个是Bundle */ sendOrderedBroadcast(intent, null, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String resultData = getResultData(); Log.d("tag", "我是最终广播接收者:我收到的数据是:" + resultData); Log.d("tag", "ThreadName=" + Thread.currentThread().getName()); } }, handler, 0, "每人发1w元.", null);}
//无序广播的接收public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String stringExtra = intent.getStringExtra("data"); Toast.makeText(context, "收到广播:" + stringExtra, Toast.LENGTH_SHORT).show(); }}// 有序广播的多级接收:// 优先级第一级public class ProvinceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 1. 先获取到初始化的数据 String resultData = getResultData(); Log.d("tag", "省政府收到的钱是:" + resultData); Log.d("tag", "省政府线程:" + Thread.currentThread().getName()); // 拦截广播 abortBroadcast(); // 2. 修改数据,然后再设置出去 // setResultData("每人5k元."); }}// 优先级第二级public class CityReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { /* * 1. 先获取到初始化的数 */ String resultData = getResultData(); Log.d("tag", "市政府收到的钱是:" + resultData); /* * 2. 修改数据,然后再设置出去 */ setResultData("每人1k元."); }}//XML文件的注册.<receiver android:name="com.example.receivermyBroadcast.MyReceiver"> <intent-filter > <action android:name="com.itheima.mybroadcast.action"/> </intent-filter> </receiver> <receiver android:name="com.example.receivermyBroadcast.ProvinceReceiver"> <intent-filter android:priority="1000" > <action android:name="com.itheima.orderedbroadcast.sendmoney"/> </intent-filter> </receiver> <receiver android:name="com.example.receivermyBroadcast.CityReceiver"> <intent-filter android:priority="500" > <action android:name="com.itheima.orderedbroadcast.sendmoney"/> </intent-filter> </receiver> <receiver android:name="com.example.receivermyBroadcast.CountryReceiver"> <intent-filter android:priority="100" > <action android:name="com.itheima.orderedbroadcast.sendmoney"/> </intent-filter> </receiver>
02. 权限自定义广播
//发送广播public void send(View view){ Intent intent = new Intent(); intent.setAction("com.itheima.mypermission.action"); //参数2:自定义的权限 sendBroadcast(intent, "com.itheima.permission.receiveMyBroadcast");}//XML文件实现<!-- 声明自定义权限 --><permission android:name="com.itheima.permission.receiveMyBroadcast" android:protectionLevel="normal"></permission><!-- 还需使用自己的权限 --><uses-permission android:name="com.itheima.permission.receiveMyBroadcast"/>注意这里有个权限等级,如果是危险的级别,在6.0的系统需要我们去动态去注册该权限//接收广播<!-- 使用别人的权限 --><uses-permission android:name="com.itheima.permission.receiveMyBroadcast"/> <!-- 注册该权限就可以了--><receiver android:name="com.example.receiverPermissionBroad.MyReceiver"> <intent-filter > <action android:name="com.itheima.mypermission.action"></action> </intent-filter></receiver>
03. 特殊的广播与接收者
- 特殊的广播与接收者,频繁的操作:锁屏与解屏,电量的变化等
- 用动态注册方式注册,注意需要反注册,清单文件里注册无效
//锁屏与解屏,注意:在这个地方,只要界面一退出,该广播就失效可以采用在服务中注册广播的方式,public class MainActivity extends Activity {private ScreenReceiver screenReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); screenReceiver = new ScreenReceiver(); IntentFilter intentFilter = new IntentFilter(); // IntentFilter可以添加多个Action intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); registerReceiver(screenReceiver, intentFilter);}class ScreenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 如何区分到底是哪个事件 if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { Toast.makeText(context, "高斯雷开屏了", Toast.LENGTH_SHORT).show(); } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { Toast.makeText(context, "高斯雷关屏了", Toast.LENGTH_SHORT).show(); Log.d("tag", "高斯雷关屏了"); } }}@Overrideprotected void onDestroy() { super.onDestroy(); if (screenReceiver != null) { unregisterReceiver(screenReceiver); screenReceiver = null; }}public class MainActivity extends Activity { private ScreenReceiver screenReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); screenReceiver = new ScreenReceiver(); IntentFilter intentFilter = new IntentFilter(); // IntentFilter可以添加多个Action intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); registerReceiver(screenReceiver, intentFilter); } class ScreenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 如何区分到底是哪个事件 if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { Toast.makeText(context, "高斯雷开屏了", Toast.LENGTH_SHORT).show(); } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { Toast.makeText(context, "高斯雷关屏了", Toast.LENGTH_SHORT).show(); Log.d("tag", "高斯雷关屏了"); } } } @Override protected void onDestroy() { super.onDestroy(); if (screenReceiver != null) { unregisterReceiver(screenReceiver); screenReceiver = null; } }}
04. Android系统常见的广播事件
- IP拨号器(有序广播,最终广播)
- 监听手机的网络状态(无序广播)
- 监听开机启动(无序广播)
- 拦截短信(有序广播)
- sd状态的监听
- 监听应用的安装与卸载(无序广播)
//1. IP拨号器(有序广播,最终广播)public class IPBroadCastReceiver extends BroadcastReceiver { // 当该广播接收者接收到广播的时候,被系统回调该方法 @Override public void onReceive(Context context, Intent intent) { // 1. 获取用户拨打的号码 String num = getResultData(); //String num = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); // 2. 获取用户保存的ip号码 SharedPreferences sharedPreferences = context.getSharedPreferences("config", Context.MODE_PRIVATE); String ip = sharedPreferences.getString("ipnum", ""); // 3. 修改号码为ip+号码 // 4. 将修改好的号码设置出去 setResultData(ip + num); }}//注册广播接收者<receiver android:name="com.example.ipcaller.IPBroadCastReceiver"> <!-- 添加一个意图过滤器,不然过滤不到Intent,因为广播的发送其实就是发送的Intent --> <intent-filter > <action android:name="android.intent.action.NEW_OUTGOING_CALL"/> </intent-filter></receiver>//定义权限该权限系统是不会提示.<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
//2. 监听手机的网络状态(无序广播)public class MainActivity extends Activity { private TextView tv_state; private NetStateReceiver netStateReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_state = (TextView) findViewById(R.id.tv_state); /* * 1. 注册广播 * 参数1:广播接收者对象 * 参数2:意图过滤器 */ netStateReceiver = new NetStateReceiver(); //封装一个IntentFilter IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); registerReceiver(netStateReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); /* * 2. 取消注册的广播(反注册) */ if (netStateReceiver!=null) { unregisterReceiver(netStateReceiver); netStateReceiver = null; } } class NetStateReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //通过并更新当前的网络状态 /* * 对于网络状态改变的广播,我们需要重新编写代码获取状态 */ getState(null); Toast.makeText(context, "监听到网络状态改变了额", Toast.LENGTH_SHORT).show(); } } public void getState(View view){ ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); //获取当前可用的网络,如果当前没有可用的网络,返回null NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); if (activeNetworkInfo==null) { tv_state.setText("当前没有可用的网络"); tv_state.setTextColor(Color.parseColor("#ff0000")); }else { //获取当前网络的名称"MOBILE","WIFI" String typeName = activeNetworkInfo.getTypeName(); //如果是"MOBILE"类型网络,我们可以进一步获取4G(LET)或者3G String subtypeName = activeNetworkInfo.getSubtypeName(); tv_state.setTextColor(Color.BLUE); tv_state.setText("当前网络类型:"+typeName+"/"+subtypeName); } }}//权限<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
//3. 监听开机启动(无序广播)public class BootStartReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d("tag", "监听到开机了"); Toast.makeText(context, "监听到开机了", Toast.LENGTH_LONG).show(); //启动MainActivity Intent intent2 = new Intent(context, MainActivity.class); /* * 如果第从一个非Activity中启动其他Activity,那么在使用Intent的时候需要让其创建一个新的任务栈 */ intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent2); }}//权限 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>//注册 <receiver android:name="com.example.listenbootStart.BootStartReceiver" > <intent-filter > <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter></receiver>
//4. 拦截短信(有序广播)public class BlackNumReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { /* * 1. 获取sp中的黑名单 */ SharedPreferences sharedPreferences = context.getSharedPreferences("config", Context.MODE_PRIVATE); String blacknum = sharedPreferences.getString("blacknum", ""); if (TextUtils.isEmpty(blacknum)) { Log.d("tag", "用户不想拦截任何短信"); return; } /* * 2. 获取广播中的短信 */ Bundle bundle = intent.getExtras(); Object[] objs = (Object[]) bundle.get("pdus"); for(Object obj : objs){ byte[] pdu = (byte[]) obj; SmsMessage smsMessage = SmsMessage.createFromPdu(pdu); /* * 3. 判断短信的发送者是否是黑名单用户发送过来的 */ String address = smsMessage.getOriginatingAddress(); //获取短信正文 String messageBody = smsMessage.getMessageBody(); /* * 4. 如果是 就拦截,否则啥够不干 */ if (address.equals(blacknum)) { Log.d("tag", "拦截了短信:"+address+"/"+messageBody); //拦截广播 abortBroadcast(); }else { Log.d("tag", "放行了一个短信:"+address+"/"+messageBody); } } }}//权限<uses-permission android:name="android.permission.RECEIVE_SMS"/>//注册 <receiver android:name="com.example.abortSms.BlackNumReceiver"> <intent-filter android:priority="1000" > <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver>
//5. sd状态的监听public class SdcardStateReceiver extends BroadcastReceiver { //当sd状态发生改变的时候执行 @Override public void onReceive(Context context, Intent intent) { //获取到当前广播的事件类型 String action = intent.getAction(); if ("android.intent.action.MEDIA_MOUNTED".equals(action)) { System.out.println("说明sd卡挂载了 ...."); }else if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) { System.out.println("说明sd卡卸载了 "); } }} <receiver android:name="com.itheima.sdcardstate.SdcardStateReceiver"> <intent-filter > <action android:name="android.intent.action.MEDIA_MOUNTED"/> <action android:name="android.intent.action.MEDIA_UNMOUNTED"/> <!--小细节 这里需要配置一个data 约束类型叫file 因为sd里面存的数据类型是file --> <data android:scheme="file"/> </intent-filter> </receiver>
//6. 监听应用的安装与卸载(无序广播)public class AppStateReceiver extends BroadcastReceiver { //当有新的应用被安装 了 或者有应用被卸载 了 这个方法调用 @Override public void onReceive(Context context, Intent intent) { //获取当前广播事件类型 String action = intent.getAction(); if ("android.intent.action.PACKAGE_INSTALL".equals(action)) { //该事件作为保留字,不起任何作用 }else if ("android.intent.action.PACKAGE_ADDED".equals(action)) { System.out.println("应用安装了22222"); }else if("android.intent.action.PACKAGE_REMOVED".equals(action)){ System.out.println("应用卸载了"+intent.getData()); } }} <receiver android:name="com.itheima.appstate.AppStateReceiver" > <intent-filter> <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事件生效 还需要 配置一个data --> <data android:scheme="package" /> </intent-filter> </receiver>
5. 电话拦截的实现,拓展内容,涉及反射底层源代码
- 需求 : 拦截黑名单号码发送的短信
- 实现 :
- 权限 android.permission.CALL_PHONE
- 通过TelephonyManager监听电话的状态
- 拦截电话需要调用远程服务,通过androidxref下载对应的系统源文件
- 如果使用原生Android.jar内的API,必须使用Android Studio编译工程.
- 代码 :
- 注意 : 需要拷贝对应的远程服务的AIDL文件到src目录
- 注意权限 : CALL_PHONE / READ_PHONE_STATE
// 获取TelephonyManager,能够监听来电的手机号码,付出的号码能够监听,但是获取不到手机号码,只能用广播的形式获取//挂断电话的逻辑TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);PhoneListener listener = new PhoneListener();// 监听系统的电话状态tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);//只能够监听来电的手机号码,打出去的号码监听不到.class PhoneListener extends PhoneStateListener { @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); // 判断状态是否是响铃状态 if (state == TelephonyManager.CALL_STATE_RINGING) { // 判断号码是否为黑名单号码 BlackDBDAO dao = new BlackDBDAO(InterceptService.this); int type = dao.getType(incomingNumber); if (type == BlackBean.TYPE_TEL || type == BlackBean.TYPE_ALL) { // 获取远程服务 try { Class<?> clazz = Class.forName("android.os.ServiceManager"); Method method = clazz.getDeclaredMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE); ITelephony telephony = ITelephony.Stub.asInterface(binder); // 挂断电话 telephony.endCall(); } catch (Exception e) { e.printStackTrace(); LogUtils.e("错误 : " + e.toString()); } } } }// 释放资源 tm.listen(listener, PhoneStateListener.LISTEN_NONE);
- 监听呼出电话,需要权限 android.permission.PROCESS_OUTGOING_CALLS
* 监听呼入的号码, 需要使用TelephonyManager,监听不到来电的号码
* 监听呼出的号码, 需要使用系统广播
//监听号码的逻辑public class LocationService extends Service { private TelephonyManager tm; private PhnStateLisner listener; private OutgoingReceiver receiver; @Override public void onCreate() { super.onCreate(); // 获取TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); listener = new PhnStateLisner(); // 监听电话状态 tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); // 注册监听呼出状态的广播 receiver = new OutgoingReceiver(); IntentFilter filter = new IntentFilter(); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL); registerReceiver(receiver, filter); } @Override public void onDestroy() { super.onDestroy(); // 取消监听 tm.listen(listener, PhoneStateListener.LISTEN_NONE); unregisterReceiver(receiver); } // 自己实现的PhoneStateListener class PhnStateLisner extends PhoneStateListener { @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); // 如果当前电话状态是响铃状态,查询号码归属地,并显示 if (state == TelephonyManager.CALL_STATE_RINGING) { String location = QueryLocationDAO.queryLocation(LocationService.this, incomingNumber); Toast.makeText(LocationService.this, location, Toast.LENGTH_SHORT).show(); } } } // 自己实现的监听电话呼出状态的广播 class OutgoingReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String num = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); Toast.makeText(LocationService.this, num, Toast.LENGTH_SHORT).show(); } } @Override public IBinder onBind(Intent intent) { return null; }}
6. 广播的其他特点
- 特殊的广播接收者只能够使用动态注册
- 在4.0后,第一次安装应用的时候必须得有界面,这样子广播接收者才生效
- 如果用户点击了设置 页面的强行停止按钮,那么广播接收也是不生效的.
- 跨进程传递数据
- 应用之间的相互唤醒
0 0
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadCastReceiver
- BroadcastReceiver
- broadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- BroadcastReceiver
- 用 KVM 搭建web集群实验笔记 - LVS和Keeplived负载均衡(DR模式)
- [模板]最大01子矩阵
- 利用redis实现的分布式锁
- Windows+caffe+libsvm对图片数据集的分类
- C++基础 内置类型和类类型的默认初始化和值初始化
- BroadCastReceiver
- Markdown 语法手册 (完整整理版)
- jmx配合jvisualvm远程监控Java程序
- Caffe做分类初步学习以及遇到的一些坑
- 输出二叉树叶子节点数目
- Service
- μC/OS-Ⅱ的中断和时钟(二)
- OSGi - 第02章 Felix线程
- ContentPrivider