BroadCastReceiver

来源:互联网 发布:社交媒体 大数据 编辑:程序博客网 时间:2024/05/16 10:48

BroadCastReceiver组件

  1. 广播的发送与接收
  2. 自定义权限广播
  3. 特殊的广播与接收者
  4. Android系统常见的广播事件
  5. 电话拦截的实现,拓展内容,涉及反射底层源代码
  6. 广播的其他特点

01-广播的发送与接收

  1. 无序广播特点:无序广播不可以被拦截,数据不能够修改,sendBroadCast(Intent)

    普通广播是完全异步(就是不会被某个广播接收者终止)的,可以在同一时刻(逻辑上)被所有接收者接收到(其实被接收者接收到也是由顺序的,接收者配置的优先级越高,越先接收到,也就是说广播接收者的优先级对于无序广播也是有用的),消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播的传播。

  2. 有序广播特点:有序广播可以被拦截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. 特殊的广播与接收者

  1. 特殊的广播与接收者,频繁的操作:锁屏与解屏,电量的变化等
  2. 用动态注册方式注册,注意需要反注册,清单文件里注册无效

//锁屏与解屏,注意:在这个地方,只要界面一退出,该广播就失效可以采用在服务中注册广播的方式,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系统常见的广播事件

  1. IP拨号器(有序广播,最终广播)
  2. 监听手机的网络状态(无序广播)
  3. 监听开机启动(无序广播)
  4. 拦截短信(有序广播)
  5. sd状态的监听
  6. 监听应用的安装与卸载(无序广播)

//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. 广播的其他特点

  1. 特殊的广播接收者只能够使用动态注册
  2. 在4.0后,第一次安装应用的时候必须得有界面,这样子广播接收者才生效
  3. 如果用户点击了设置 页面的强行停止按钮,那么广播接收也是不生效的.
  4. 跨进程传递数据
  5. 应用之间的相互唤醒
0 0
原创粉丝点击