四大组件:BroadCastReceiver广播

简介

BroadCastReceiver:广播接收者,可以接受手机电量变化、短信、电话、app的安装与卸载等都可以接受到这些广播(这些事系统发出的广播),当然我们还可以自定义广播,这就我们自己写发送广播的代码。

分类:

有序广播和无序广播
有序广播:是可以拦截的,可以设置优先级(数值越大,越先接收广播)
无序广播:不可以被拦截,没有优先级。

有关方法:

sendBroadcast(intent);发送广播
sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)发送有序广播
abortBroadcast();取消广播,只有有序广播才可以调用该方法,无序广播调用会报错BroadcastReceiver trying to return result during a non-ordered broadcast

这里写图片描述

如果是静态广播,那么不需要在onReceive(...)中判断action,如果是动态注册,需要判断action

静态广播接收者BroadCastReceiver

注册广播接收者有2种方法,代码中注册(动态注册)和AndroidManifest.xml中注册(静态注册),下面的案例没说明动态注册的都是静态注册。

系统发出的广播,我们只做接收。常见的如下:
- 打电话 Receiver
- SD卡状态 Receiver
- 来短信 Receiver
- app的安装与卸载 Receiver
- 开机启动 Receiver

打电话 Receiver

打电话,若是长途,则广播中给手机号添加ip:123456

这里写图片描述

    @Override
    public void onReceive(Context context, Intent intent) {
        //获取保存的ip
        SharedPreferences sp = context.getSharedPreferences("config", context.MODE_PRIVATE);
        String ip = sp.getString("ip", "17951");

        //获取拨进来的号码
        String number = getResultData();
        //以0开头,则是长途,则在号码前加ip
        if (number.startsWith("0")) {
            setResultData(ip + number);
        }
    }
<!--在androidManifest中注册的广播是持久广播,app退出仍然有效。  -->
<!-- 声明receiver 添加action -->
<receiver android:name="com.cqc.ipnumber.OutGoingCallBroadCastReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>
<!-- 添加外拨电话权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

SD卡状态 Receiver

 根据action判断sd卡是挂载还是卸载。注意卸载sd卡的action是UNMOUNTED,不是REMOVE
@Override
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {// 挂载
        Log.d(TAG, "sd卡挂载");
    } else if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) {
        Log.d(TAG, "sd卡卸载");
    }
}
<!-- 声明receiver -->
 <receiver android:name="com.cqc.sdstatelistener.SdStateReceiver" >
     <intent-filter>
         <action android:name="android.intent.action.MEDIA_MOUNTED" />
         <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
         <!-- sd卡状态比较特殊,除了设置action,还需要data -->
         <data android:scheme="file" />
     </intent-filter>
 </receiver>

来短信 Receiver

广播接收者:

    @Override
    public void onReceive(Context context, Intent intent) {
        //转换成数组
        Object[] objects = (Object[]) intent.getExtras().get("pdus");
        //遍历数组,湖区sms对象
        for (Object object : objects) {
            SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
            //获取短信内容和发布者手机号
            String content = sms.getMessageBody();
            String originNumber= sms.getOriginatingAddress();
            Log.d(TAG, "content="+content+"____originNumber"+originNumber);
        }
    }
<receiver android:name="com.cac.smsreceiver.SmsReceiver" >
       <intent-filter>

           <!-- 处于安全性考虑,android没有提示短信监听的action,但仍然可以使用 -->
           <action android:name="android.provider.Telephony.SMS_RECEIVED" />
       </intent-filter>
   </receiver>
 <!-- 短信监听的权限 -->
  <uses-permission android:name="android.permission.RECEIVE_SMS" />

把androidManifest.xml的启动的actiivty的intent_filter注释掉,就没有界面了,但是海驿拿到短信, api4.0后,注释掉intent_filter,就拿不到短信了。

app的安装与卸载 Receiver

这里写图片描述

@Override
public void onReceive(Context context, Intent intent) {

String action = intent.getAction();
    if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {// 挂载
        Log.d(TAG, "安装");
    } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
        Log.d(TAG, "卸载");
    }
}
<receiver android:name="com.cqc.installreceiver.InstallReceiver">
    <intent-filter >
        <action android:name="android.intent.action.PACKAGE_ADDED"/>
        <action android:name="android.intent.action.PACKAGE_REMOVED"/>
        <!-- 安装卸载还需要添加data -->
        <data android:scheme="package"/>
    </intent-filter>
</receiver>

开机启动 Receiver

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "intent2");
        Intent intent2 = new Intent(context, MainActivity.class);
        intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent2);

        String action = intent.getAction();
        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
            Log.d(TAG, "Intent.ACTION_BOOT_COMPLETED");

        }
    }
 <receiver android:name="com.cqc.bootreceiver.BootReceiver" >
      <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
  </receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

自定义广播接收者

自定义广播需要设置action,可以获取intent中的数据。

基本使用

自定义广播,在Button的点击监听中发送广播,在receiver中根据action,从intent中取值。

这里写图片描述

发送广播:

Intent intent = new  Intent();
intent.setAction("MyReceiver");
intent.putExtra("name", "奥巴马");
sendBroadcast(intent);

MyReceiver :

public class MyReceiver extends BroadcastReceiver {

    private static final String TAG = "MyReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "MyReceiver--name="+intent.getStringExtra("name"));
        //取消广播
        abortBroadcast();
    }
}

在AndroidManifest.xml中配置receiver:

<receiver android:name="com.cqc.custombroadcast.MyReceiver">
   <intent-filter >
       <action android:name="MyReceiver"/>
   </intent-filter>
</receiver>

自定义有序广播

demo:国家发布政令后,先到省政府,再到市政府,再到县政府…,这里只设置这3级,有先后顺序。点击Button发送广播,一次向下传递。

点击Button发送广播:

 btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //发送自定义广播
                Intent intent = new Intent();
                intent.setAction("customOrderReceiver");
                intent.putExtra("commond", "全国各级部门应该加强安全防范措施");
//              sendBroadcast(intent);//这是无序广播
                /**
                 * 这是有序广播,参数分别是:
                 * Intent intent:intent对象
                 * String receiverPermission: 接收者权限
                 * BroadcastReceiver resultReceiver:最后一个接收者,不为null,则最后的receiver会接收2次。
                 * Handler scheduler, null
                 * int initialCode  状态码
                 * String initialData,  传递的数据,intent.putExtra(...)
                 * Bundle initialExtras:null
                 */
                sendOrderedBroadcast(intent, null, new CountyReceiver(), null, 1, null, null);
            }
        });

省级先接到通知

public class ProviceReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("tag", "省级部门接到中央命令+content="+intent.getStringExtra("commond"));
    }
}

然后是市级接到通知

public class CityReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("tag", "市级部门接到中央命令+content="+intent.getStringExtra("commond"));
    }
}

最后是县级接到通知

public class CountyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("tag", "县级部门接到中央命令+content="+intent.getStringExtra("commond"));
    }
}

注意:

1 上面的先后级别是根据广播接收者的priority(优先级)决定的。是在配置receiver时设置的。

 <receiver android:name="com.cqc.customorderreceiver.ProviceReceiver" >
            <intent-filter android:priority="3" >
                <action android:name="customOrderReceiver" />
            </intent-filter>
        </receiver>
 <receiver android:name="com.cqc.customorderreceiver.CityReceiver" >
     <intent-filter android:priority="2" >
         <action android:name="customOrderReceiver" />
     </intent-filter>
 </receiver>
 <receiver android:name="com.cqc.customorderreceiver.CountyReceiver" >
     <intent-filter android:priority="1" >
         <action android:name="customOrderReceiver" />
     </intent-filter>
 </receiver>

2 调用方法sendOrderedBroadcast(…)发送有序广播的时候若指定了最后接收者( resultReceiver),那么 resultReceiver会收到2次广播。
这里写图片描述

动态注册广播接收者

与静态相比区别是:

代码上:

1 不需要再AndroidManifest.xml中注册
2 调用registerReceiver(receiver, filter)注册接收者

理解上:

静态注册的广播接收者:当app关闭的时候也是有效的,也可以接受到服务器发出的广播。
动态注册的广播接收者:当app关闭的时候,不会接受到广播。因为我们是在onCreate()中注册的,而不是在AndroidManifest.xml中注册。

下面的是锁屏和开锁的的广播接收者,当我们打开这个app的时候,按住手机电源键锁屏和接收会打印出log,但是当我们关闭app的时候,再按住手机电源键锁屏和接收则不会打印出log

这里写图片描述

Demo1:

public class MainActivity extends Activity {

    private MyBroadcastReceiver receiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        receiver = new MyBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.SCREEN_ON");//添加action
        filter.addAction("android.intent.action.SCREEN_OFF");
        registerReceiver(receiver, filter);//注册广播接收者
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(receiver);//取消广播接收者
        super.onDestroy();
    }

    //创建广播接收者类
    public class MyBroadcastReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("android.intent.action.SCREEN_OFF".equals(action)) {
                System.out.println("锁屏");
            } else if("android.intent.action.SCREEN_ON".equals(action)){
                System.out.println("解锁");
            }           
        }
    }    
}

代码:https://git.oschina.net/beifang2008/DongTaiBroadCastReceiver

Demo2:

public class MainActivity extends Activity {
    private MyBroadcastReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("auto_finish");
                sendBroadcast(intent);              
            }
        });


        receiver = new MyBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("finish");// 添加action
        registerReceiver(receiver, filter);// 注册广播接收者   
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(receiver);// 取消广播接收者
        super.onDestroy();
    }

    // 创建广播接收者类
    public class MyBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("finish".equals(action)) {
                finish();
            }
        }
    }
}

sendBroadcast(intent)与sendStickyBroadcast(intent)的区别?

区别主要是在动态注册广播中才有,在静态注册中是一样的。
sendBroadcast(intent):当发送广播在注册广播前时,接收者是接收不到广播的。
sendStickyBroadcast(intent):当发送广播在注册广播前时,接收者是可以接收到广播的。sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的 时候,又会接受到它。

Demo:https://git.oschina.net/beifang2008/DongTaiBroadCastReceiver2

LocalBroadcastManager

Android高效安全的本地广播LocalBroadcast完全解析
LocalBroadcastManager只可以动态注册广播。

获取LocalBroadcastManager对象,单利模式

LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);

设置InentFilter,intentFilter和intent都必须设置action

IntentFilter filter = new IntentFilter();
filter.addAction(localAction);

注册

broadcastManager.registerReceiver(receiver, filter);

发送Broadcast

Intent intent = new Intent(localAction);
broadcastManager.sendBroadcast(intent);

取消注册

broadcastManager.unregisterReceiver(receiver);

android.support.v4.content.LocalBroadcastManager工具类,可以实现在自己的进程内进行局部广播发送与注册,使用它比直接通过sendBroadcast(Intent)发送系统全局广播有以下几个好处

  • 因广播数据在本应用范围内传播,你不用担心隐私数据泄露的问题。
  • 不用担心别的应用伪造广播,造成安全隐患。
  • 相比在系统内发送全局广播,它更高效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值