(七)Android基础系列之:BroadcastReceiver

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/androidzf/article/details/87860328

一、按广播发送的特点:默认情况下,广播接收者的接收顺序就是在功能清单文件中的注册顺序

  • A:正常广播:广播在同一时刻一起发送,接收者会同时收到,其中一个接收者不能终止其它接收者接收广播。
    实例化意图对象并指定意图对象的action
    Intent intent=new Intent(“android.intent.action.hsj”);
    发送正常广播
    this.sendBroadcast(intent);

  • B:有序广播:根据广播的优先级决定哪个广播接收者先收到广播,并且可以根据需要终止广播,让优先级低的广播永远收不到广播.
    如果广播接收方的优先级相同,则接收信号的顺序和注册的顺序一致.
    如果广播接收者的优先级不同,则优先级高的接收者优先收到广播,并且高优先级的接收者可以终止广播,让优先级低的广播接收者永远收不到广播
    广播接收者的优先级的取值:-1000到1000,数字越大,优先级越高

<receiver android:name=".receivers.BroadcastReceiverOne">
    <intent-filter android:priority="100">
        <action android:name="hsj"/>
    </intent-filter>
</receiver>
<receiver android:name=".receivers.BroadcastReceiverTwo">
    <intent-filter android:priority="500">
        <action android:name="hsj"/>
        <action android:name="wcf"/>
    </intent-filter>
</receiver>
<receiver android:name=".receivers.BroadcastReceiverThree">
    <intent-filter android:priority="1000">
        <action android:name="hsj"/>
         <action android:name="wcf"/>
    </intent-filter>
</receiver>

发送有序广播:

context.sendOrderedBroadcast(intent,null);
this.sendOrderedBroadcast(intent,null);

发送有序广播并且指定最终广播对象,所谓最终广播对象是:即使前面已经最终了广播,作为最终广播对象一定会收到广播信号的.

this.sendOrderedBroadcast(
                intent,//意图对象
                null,
                new BroadcastReceiverOne(),//指定最终广播对象
                null,
                100,//初始化码,
                null,
                null
        );

终止广播信号的发送,使其后面的广播接收者收不到广播信号

this.abortBroadcast();
  • C:粘滞广播:这种广播会常驻内存,可以先发送广播,之后再注册广播接收者仍然能够收到之前发送的广播.
    注册发送粘滞广播需要的权限 发送粘滞广播,必须在功能清单文件中注册发送粘滞广播的权限
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

注册广播

IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("hsj");

通过上下文对象动态注册广播接收者

this.registerReceiver(broadCastReceiverTwo, intentFilter);

发送广播

Intent intent=new Intent("hsj");
this.sendStickyBroadcast(intent);

取消注册指定的广播接收者

this.unregisterReceiver(broadCastReceiverTwo);

二、按广播的有效期:

android四大组件中,只有广播接收者可以通过java代码进行注册,其它的都必须在功能清单文件中进行注册;

  • A:静态广播:在功能清单文件中注册的广播,即使程序退出,一旦有合适的广播发送仍然能够收到广播的消息
  • B:动态广播:在java代码中使用context.registerReceiver(receiver,interfilter);这个方法注册的广播,程序一旦退出,广播接收者就再也收不到广播
    消息了。
动态注册广播
IntentFilter intentFilter=new IntentFilter("android.intent.action.hsj");
this.registerReceiver(this.broadcastReceiverTwo, intentFilter);
发送粘滞广播
Intent intent=new Intent("android.intent.action.hsj");
this.sendStickyBroadcast(intent);
取消注册广播
this.unregisterReceiver(this.broadcastReceiverTwo);

自定义广播接收者的步骤:

  • 1.编写一个类继承BroadcastReceiver并重写它的声明周期函数:onReceive(Context context, Intent intent)
class BroadcastReceiverOne extends BroadcastReceiver {
   @Override
    public void onReceive(Context context, Intent intent) {
    }
}
  • 2.在功能清单文件中注册广播接收者,这种广播成为静态广播;通过Java代码进行注册,这种广播成为动态广播
<receiver android:name=".receiver.BroadcastReceiverOne">
    <intent-filter>
    <action android:name="android.intent.action.hsj"/>
    </intent-filter>
</receiver>

广播接收者的生命周期就是onReceive(Context context, Intent intent)方法的执行期间,这个方法默认运行在主线程中,因此不能做耗时
操作,另外广播接收者的生命周期最长不要超过10秒,因为超过10秒后可能作为被杀死的候选对象,因此不安全.

可以在广播接收者的生命周期函数onReceive(Context context, Intent intent)中启动服务做耗时操作.

三、应用

1、自定义检查手机网络状态是否切换的广播接收者

public class PhoneNetStateCheckBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action=intent.getAction();
        //ConnectivityManager.CONNECTIVITY_ACTION即android.net.conn.CONNECTIVITY_CHANGE
        if(ConnectivityManager.CONNECTIVITY_ACTION.equals(action)){//说明手机的网络状态发生了化
            testConnectionState(context);
        }else{
            Toast.makeText(context, "当前的广播不是手机网络状态切换的广播!",Toast.LENGTH_LONG).show();
        }
    }
    /**
     * 检查手机网络状态的变化
     * @param context
     */
    private void testConnectionState(Context context) {
        ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo= connectivityManager.getActiveNetworkInfo();
        if(networkInfo!=null&&networkInfo.isConnected()){
            if(networkInfo.getType()==ConnectivityManager.TYPE_WIFI){
                Toast.makeText(context, "当前手机连接了WIFI网络!", Toast.LENGTH_LONG).show();
            }else if(networkInfo.getType()==ConnectivityManager.TYPE_MOBILE){
                Toast.makeText(context, "当前手机连接了3G网络!", Toast.LENGTH_LONG).show();
            }else{
                Toast.makeText(context, "当前手机连接了未知网络!", Toast.LENGTH_LONG).show();
            }
        }else{
            Toast.makeText(context, "当前无网络!", Toast.LENGTH_LONG).show();
        }
    } 
}

2、短信拦截

  • 需要的权限:
<!-- 注册接收短信的权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<!-- 注册发送短信的权限 -->
<uses-permission android:name="android.permission.SEND_SMS"/>
  • 注册广播
<!--注册短信拦截器的广播接收者-->
<receiver android:name=".receivers.SmsInterceptorBroadcastReceiver">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>
  • 自定义短信拦截器的广播接收者
public class SmsInterceptorBroadcastReceiver extends BroadcastReceiver {
    /**
     * 当手机收到短信时系统会发送一个广播,这个广播对应的意图的动作为android.provider.Telephony.SMS_RECEIVED
     */
    private String action="android.provider.Telephony.SMS_RECEIVED";
    @Override
    public void onReceive(Context context, Intent intent) {
        String strAction=intent.getAction();
        System.out.println("SmsInterceptorBroadcastReceiver.onReceive(Context context, Intent intent).strAction="+strAction);
        //说明手机收到短信并且系统发送了广播
        if(action.equals(strAction)){
            //通过意图得到Bundle对象
            Bundle bundle=intent.getExtras();
            //通过bundle对象调用get()方法传递的键为pdus则得到一个短信对象数组对应的对象
            Object[] objs=(Object[]) bundle.get("pdus");
            for(Object obj:objs){
                //将短信对象转化成字节数组
                byte[] data=(byte[]) obj;
                //根据字节数组得到短信消息对象
                SmsMessage smsMessage=SmsMessage.createFromPdu(data);
                //得到发送短信手机的电话号码
                String senderAddress=smsMessage.getOriginatingAddress();
                //得到短信内容
                String body=smsMessage.getMessageBody();
                //得到接收短信的时间
                long ldate=smsMessage.getTimestampMillis();
                //格式化日期
                SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date=new Date(ldate);
                String strDate=simpleDateFormat.format(date);
                String receiveSms=senderAddress+"在"+strDate+"时间发送了短信内容为【"+body+"】的短信内容!";
                //Toast.makeText(context, receiveSms, Toast.LENGTH_LONG).show();
                //终止接收短信的广播
                this.abortBroadcast();
                //得到短信管理器对象
                SmsManager smsManager=SmsManager.getDefault();
                String text="zhe niu shi wo de,zai gei lao zi qiang xiao xin lao zi fei le ni!";
                //发送短信
                smsManager.sendTextMessage(senderAddress, null, text, null, null);
            }
        }else{
            Toast.makeText(context, "并非收到短信的广播!", Toast.LENGTH_LONG).show();
        }
    }
}

3、电话拦截

  • 所需权限
<!-- 注册处理外拨电话的权限 -->
 <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
  • 功能清单注册广播
<!-- 注册电话拦截器的广播接收者
        android.intent.action.NEW_OUTGOING_CALL:当用户外拨电话时anroid系统会发送一个广播,这个广播对应的意图中的action即为:
        android.intent.action.NEW_OUTGOING_CALL
         -->
<receiver android:name=".receivers.PhoneInterceptorBroadcastReceiver">
       <intent-filter>
             <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
       </intent-filter>
</receiver>
  • 自定义电话拦截器的广播接收者
public class PhoneInterceptorBroadcastReceiver extends BroadcastReceiver {
 
    private String action="android.intent.action.NEW_OUTGOING_CALL";
    @Override
    public void onReceive(Context context, Intent intent) {
        String strAction=intent.getAction();
        //外拨电话的广播
        if(action.equals(strAction)){
            //得到外拨电话的电话号码
            String phone=this.getResultData();
            if(phone.contains("5556")){
                //将电话号码置空
                this.setResultData(null);
            }
        }else{
            Toast.makeText(context, "并不是外拨电话的广播",Toast.LENGTH_LONG).show();
        }
     
    }
}

猜你喜欢

转载自blog.csdn.net/androidzf/article/details/87860328