定义

广播,是一个全局的监听器,属于Android四大组件之一。Android广播分为两个角色:广播发送者、广播接收者。

应用场景

1、App接受系统发出的系统广播;

2、不同App之间的组件之间消息通信;

3、同一个App的不同组件之间的消息通信;

广播类型

1、标准广播

2、有序广播

监听电量变化状态(例子一)

1、广播接收者

小技巧:.notnull自动补全

报错点:setText不能传int类型

/**
     * 第一步,创建一个广告接收者,继承自BroadcastReceiver
     */
    private class BatteryLevelReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG,"action is == " +action);
            if (Intent.ACTION_BATTERY_CHANGED.equals(action)){
                int currentLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
                Log.d(TAG,"当前的电量为:"+currentLevel);
                //快捷键.notnull
                if (mBatteryLevel != null) {
                    //mBatteryLevel.setText(intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0)); 报错了,不能传int变量,必须为String
                    mBatteryLevel.setText("当前的电量为:" + currentLevel);
                }
                int maxBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_SCALE,0);
                float batteryPercent = currentLevel * 100.0f / maxBatteryLevel;
                Log.d(TAG,"当前的电量百分比为:"+batteryPercent + "%");
            }
        }
    }

2、添加权限

<uses-permission android:name="android.permission.BATTERY_STATS"/>

3、注册广播(动态注册)

小技巧:对代码块进行右键->Refactor->Extract->method 可以提炼函数;

private void registerBatteryReceiver() {
        //注册广播:动态注册
        //第二步,创建意图过滤器
        IntentFilter intentFilter = new IntentFilter();
        //第三步,添加要监听的广播action
        //设置频道
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //第四步,创建广播者,并且设置成成员变量,以便于取消注册,释放资源
        batteryLevelReceiver = new BatteryLevelReceiver();
        //第五步,注册广播接收者
        this.registerReceiver(batteryLevelReceiver,intentFilter);
    }

4、取消注册广播

小技巧:Ctrl + o select methods to Override选择方法重写;

@Override
    protected void onDestroy() {
        super.onDestroy();
        //第六步,取消广播注册,否则会导致内存泄露
        if(batteryLevelReceiver != null){
            unregisterReceiver(batteryLevelReceiver);
            batteryLevelReceiver = null;
            Log.d(TAG,"unregister receive");
        }
    }

5、模拟电量的adb 命令

dumpsys battery help
Battery service (battery) commands:
  help
    Print this help text.
  set [ac|usb|wireless|status|level|invalid] <value>
    Force a battery property value, freezing battery state.
  unplug
    Force battery unplugged, freezing battery state.
  reset
    Unfreeze battery state, returning to current hardware values.

监听开机广播(例子二)

1、广播接收者

新建一个类,接收到开机广播后自启动APK;

public class BootCompleteReceiver  extends BroadcastReceiver {
    private static final String TAG = "BootCompleteReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_BOOT_COMPLETED.equals(action)){
            Toast.makeText(context,"接收到开机广播",Toast.LENGTH_SHORT).show();
            Log.d(TAG,"接收到开机广播");
            Intent autonStart = new Intent(context,MainActivity.class);
            context.startActivity(autonStart);
        }
    }
}

2、添加权限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

3、注册广播(静态注册)

 android:priority="1000",可以提高优先级,会减少APP接受到广播的时间;

<receiver
            android:name=".BootCompleteReceiver">
            <intent-filter android:priority="1000">
                <action android:name= "android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>

动态注册(例子一)和静态注册(例子二)的区别

1、某些action不支持静态注册,在Intent.java的注释中会有如下的说明:

You <em>cannot</em> receive this through components declared
     * in manifests, only by explicitly registering for it with
     * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)

2、动态注册会受到activity的生命周期影响,销毁后不再监听广播(动态注册的广播要想一直监听可以注册到server里面区监听),不容易出现内存泄漏;静态注册的广播,即使Activity销毁了,仍然可以收到广播。即使杀死进程,仍然可以收到广播。

3、Android8.0以上平台,应用不能对大部分广播进行静态注册;

监听应用的安装和卸载(例子三)

1、广播接收者

public class AppStateChangeReceiver extends BroadcastReceiver {
    private static final String TAG = "AppStateChangeReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_PACKAGE_ADDED.equals(action)){
            Log.d(TAG, "有应用安装了,它的相关信息是:" + intent.getData());
        }else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)){
            Log.d(TAG, "有应用卸载了,它的相关信息是:" + intent.getData());
        }
    }
}

2、添加权限

无需添加权限,一般我们调试的时候可以先不加权限,当报错的时候我们再会过来重新加上;

3、静态注册

必须要加上data标签,否则会接收不到广播;

<receiver
            android:name=".AppStateChangeReceiver">
            <intent-filter>
                <!--应用安装-->
                <action android:name="android.intent.action.PACKAGE_ADDED"></action>
                <!--应用卸载-->
                <action android:name="android.intent.action.PACKAGE_REMOVED"></action>
                <data android:scheme="package"/>
            </intent-filter>
        </receiver>

4、小结:通过应用安装、应用卸载广播我们可以得知哪些被卸载或者被安装的APK包名,之前遇到过一个系统开发需求就是,当客户的APK OTA升级成功之后重启系统,就可以用这个方法;接收应用安装的系统广播,并判断或者的getData包名是否为指定的包名,若是则重启;

发送自定义标准广播和接收(例子四)

 1、发送自定义标准广播

新建一个SendBroadcaseActivity以及布局文件,方便调试我们把SendBroadcaseActivity作为启动activity,即把下面的代码块复制到SendBroadcaseActivity的声明中;

<intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

hint代表当输入框为空时的提示语;

onClick代表当点击按钮时执行的方法;

<EditText
        android:id="@+id/be_send_msg_input_box"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入你的广播信息"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="sendBroadcastMsg"
        android:text="发送一条广播通知"/>
public class SendBroadcaseActivity extends Activity {

    private EditText mInputBox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send);
        mInputBox = this.findViewById(R.id.be_send_msg_input_box);
    }

    /**
     * 当我们点击按钮后,会执行下面的方法
     */
    public void sendBroadcastMsg(View view){
        String content = mInputBox.getText().toString();
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_SEND_MSG);
        intent.putExtra(Constants.KEY_CONTENT,content);
        sendBroadcast(intent);
    }
}

一般自定义广播action命名为包名.常量比如:com.example.broadcastdemo.SEN_MSG

这里因为action名和键名都为常量,我们新建一个Constants.java存储常量,方便合作开发。

package com.example.broadcastdemo;

public class Constants {
    public static final String ACTION_SEND_MSG = "com.example.broadcastdemo.SEND_MSG";
    public static final String KEY_CONTENT = "content";
}

2、广播接收者

新建MessageReceiver 作为广播接收者

public class MessageReceiver extends BroadcastReceiver {
    private static final String TAG = "MessageReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action :" + action);
        String content = intent.getStringExtra(Constants.KEY_CONTENT);
        Log.d(TAG, "message :" + content);
    }
}

别忘了注册广播

<receiver android:name=".MessageReceiver">
            <intent-filter>
                <action android:name="com.example.broadcastdemo.SEND_MSG"></action>
            </intent-filter>
        </receiver>

发送自定义有序广播和接收(例子五-android:priority优先级)

1、编写三个继承Broadcast的类进行测试,并对他们进行静态注册,同时用android:priority属性设置不同的优先级;范围:-1000~1000,默认值为0;

sendOrderedBroadcast的receiverPermission参数先设置为null,在例子七讲解;

public  void SendOrderBroadCastMsg (View view){
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_SEND_ORDER_BROADCAST);
        sendOrderedBroadcast(intent,null);
    }
<receiver android:name=".HightLevelReceiver">
            <intent-filter android:priority="1000">
                <action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>

        <receiver android:name=".DefaultLevelReceiver">
            <intent-filter android:priority="0">
                <action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>

        <receiver android:name=".LowLevelReceiver">
            <intent-filter android:priority="-1000">
                <action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>

2、测试结果

1970-01-01 08:01:48.111 4876-4876/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:01:48.113 4876-4876/com.example.broadcastdemo D/DefaultLevelReceiver: default level: com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:01:48.116 4876-4876/com.example.broadcastdemo D/LowLevelReceiver: Low Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST

留一个疑问,是否可以设置 android:priority优先级属性的广播就是有序广播呢?那前面的系统开机广播算不算有序广播?

有序广播的终止广播和修改广播内容(例子六)

1、终止广播

直接修改HightLevelReceiver的onReceiver的函数让广播终止;

public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "Hight Level action:" + action);
        //终止广播
        abortBroadcast();
    }

 测试结果:

1970-01-01 08:15:55.454 30006-30006/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST

2、修改广播内容

用上面的例子继续做修改,由于前面的广播并没有内容我们用sendOrderedBroadcast方法添加内容进去’;

@Override
    public void sendOrderedBroadcast(
            Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
            Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras) {
        mBase.sendOrderedBroadcast(intent, receiverPermission,
                resultReceiver, scheduler, initialCode,
                initialData, initialExtras);
    }

原API说明文档:

android 收不到广播RECEIVE_BOOT_COMPLETED android中广播接收者的作用_静态注册

老师笔记中的解释:

  • 第一个参数,不用说了,我们发送广播就知道了,这个是意图对象,用于封装数据和设置过滤。
  • 第二个参数是权限,权限我们后面会详细说到,虽然很少用到,但是你知道这个思想,有利于你以后自己钻研android的代码。
  • 第三个参数是广播接收者,这个广播接收者是最终接收的广播接收者,用于检查数据是否有传达或者数据被修改。
  • 第四个参数是一个自定义的Hanlder,用于处理结果接收者,也就是上面那个接收者的回调。
  • 第五个参数是初始码,这个会作为结果码,通常是Activity.RESULT_OK,也就是-1。
  • 第六个参数是用于传递数据的,这个数据在各个Receiver里获取到,通过getResultData方法获取。这个其实通常为null
  • 第七个参数也是用于封装数据的,不同的是,这个用于封装数据集合,从上面的代码可以知道 ,我用来封装了一个钱的数据。

在HightLevelReceiver的onReceiver的函数获取广播内容并修改内容,DefaultLevelReceiver和LowLevelReceiver同理;

public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "Hight Level action:" + action);
        //终止广播
        //abortBroadcast();
        //接收广播内容
        Bundle resultExtras = getResultExtras(true);
        String content = resultExtras.getCharSequence("content").toString();
        Log.d(TAG, "content: " +content);
        //修改广播内容
        resultExtras.putCharSequence("content","我是被修改过的广播内容");
    }

测试结果:

1970-01-01 08:43:41.844 11517-11517/com.example.broadcastdemo D/HightLevelReceiver: Hight Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.844 11517-11517/com.example.broadcastdemo D/HightLevelReceiver: content: 我是没有被修改过的广播内容
1970-01-01 08:43:41.848 11517-11517/com.example.broadcastdemo D/DefaultLevelReceiver: default level: com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.848 11517-11517/com.example.broadcastdemo D/DefaultLevelReceiver: content: 我是被修改过的广播内容
1970-01-01 08:43:41.850 11517-11517/com.example.broadcastdemo D/LowLevelReceiver: Low Level action:com.example.broadcastdemo.SEND_ORDER_BROADCAST
1970-01-01 08:43:41.850 11517-11517/com.example.broadcastdemo D/LowLevelReceiver: content: 我是再一次被修改过的广播内容

Android广播权限(例子七-我的广播谁可以接收?)

流程:发送者定义广播权限-发送带权限的有序广播-接收者申明广播权限

发送者定义权限:

<permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>

发送带权限的有序广播

sendOrderedBroadcast(intent,Manifest.permission.ORDER_PERMISSION,null,null,Activity.RESULT_OK,null,bundle);

接收者申明广播权限(别忘了注册广播)

<uses-permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>

Android广播权限(例子八-谁可以给我这个广播接收者发送广播)

流程:接收者定义广播权限-发送者申明广播权限-发送者发送广播

接收者定义广播权限(注意有两个地方添加了com.example.broadcastdemo.WHO_CAN_SEND_ME)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasepermissiondemo">
    <!--<uses-permission android:name="com.example.broadcastdemo.ORDER_PERMISSION"/>-->
    <permission android:name="com.example.broadcastdemo.WHO_CAN_SEND_ME"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".OrderBroadcastReceiver" android:permission="com.example.broadcastdemo.WHO_CAN_SEND_ME">
            <intent-filter>
                <action android:name="com.example.broadcastdemo.SEND_ORDER_BROADCAST"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

发送者申明广播权限

<uses-permission android:name="com.example.broadcastdemo.WHO_CAN_SEND_ME"/>

发送者发送广播

sendOrderedBroadcast(intent,null,null,null,Activity.RESULT_OK,null,bundle);

Android广播权限-小结

1、谁定义权限(permission而不是<uses-permission),另一方必须得按照这个规则发送权限或者接收权限;

2、当发送者定义权限的时候,接收者必须得按照这个规则才可以接收到广播;

3、当接收者定义权限的时候,发送者必须得按照这个规则才可以接收者才可以接收到广播;