【Android】BroadcastReceiver广播机制简单了解

学而不思则罔,思而不学则殆


广播分类

广播类型说明
标准广播(normal broadcasts)是一条完全异步执行的广播,广播发出后所有的接受者几乎是在同一时刻受到广播,他们中间没有先后顺序,不能被截断
有序广播 (ordered broadcasts)一种同步执行的广播,广播发出后,同一时间只能有一个接受者受到广播,高优先级的接受者可以截断广播的发送

标准广播图示

在这里插入图片描述

有序广播图示

在这里插入图片描述

注册广播

新建一个广播接收器

新建一个类,继承BroadcastReceiver ,并重写onReveive方法

public class MyFirstReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1102",MyFirstReceiver.class.getSimpleName() + " action:" + action);
        //截断广播
        //abortBroadcast();
    }
}

动态注册

public class MainActivity extends AppCompatActivity {

    private MyFirstReceiver myFirstReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_TIME_TICK);
        myFirstReceiver = new MyFirstReceiver();
        //动态注册广播
        registerReceiver(myFirstReceiver, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消注册
        unregisterReceiver(myFirstReceiver);
    }
}

运行程序:

$ adb logcat -s zhangyu1102
--------- beginning of main
--------- beginning of system
11-02 00:43:00.034 17443 17443 D zhangyu1102: MyFirstReceiver action:android.intent.action.TIME_TICK                                                                                                                      
11-02 00:44:00.019 17443 17443 D zhangyu1102: MyFirstReceiver action:android.intent.action.TIME_TICK                                                                                                                          
11-02 00:45:00.031 17443 17443 D zhangyu1102: MyFirstReceiver action:android.intent.action.TIME_TICK                                                                                                                          

该广播每隔一分钟就发送一次。
想了解更多系统广播可以到如下的路径下面去查看:

<AndroidSDK>\platforms\<andorid版本>\data\broadcast_actions.txt
Sdk\platforms\android-27\data\broadcast_actions.txt

静态注册

动态注册广播可以自由的控制注册和注销,在灵性方面有很大的优势和选择。但是也存在缺点,就是必须需要程序启动之后才能接收广播。那么有没有什么办法可以让程序未启动的情况下也能接收广播呢?
实际上在过去的Android版本中,很多广播都可静态注册接收,但是这样存在很多恶意程序注册,从而被唤醒,严重的影响了手机的性能和CPU,因此Google每年都在消减或者限制静态注册广播的功能
在Android 8过后,所有的隐式广播都不允许静态注册的方式来接收了。隐式广播是指那些没有指定具体发送给哪个应用程序的广播。大多数系统广播都是隐式广播,但是少数的特殊的广播目前还是可以允许使用静态注册的方式来接收。具体广播可以查看:https://developer.android.google.cn/guide/components/broadcast-exceptions.html
比如:android.intent.action.BOOT_COMPLETED 开机启动广播
用该广播实现开机启动功能。

静态注册实现开机启动

广播接收器:

public class TestBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", TestBootReceiver.class.getSimpleName() + " action:" + action);
    }
}

静态注册:

        <receiver
            android:name=".broadcast.TestBootReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

注册权限:

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

系统为了保护用户的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操作,必须在AndroidManifest.xml中进行权限声明。

重启手机(模拟器)过后,你通过命令可以发现进程已经被拉起来了:
在这里插入图片描述
在这里插入图片描述
这里就简单实现了一个开机自启动功能的逻辑。

静态注册的广播和Application接收的顺序

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("zhangyu1112", "App onCreate:" + this);
    }
}

重启手机:

86183@DESKTOP-MKB5ERF MINGW64 ~/Desktop
$ adb logcat -s zhangyu1112
- waiting for device -
--------- beginning of main
--------- beginning of system
11-12 06:19:30.650  3753  3753 D zhangyu1112: App onCreate:com.example.broadcastdemo.App@a371b5f
11-12 06:19:30.651  3753  3753 D zhangyu1112: MyBootReceiver action:android.intent.action.BOOT_COMPLETED

可以看到,是Application 的onCreate方法先走,然后才是onReceive。

发送广播

发送普通广播

自定义两个广播:

public class MyFirstReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", MyFirstReceiver.class.getSimpleName() + " action:" + action);
        //截断广播
        //abortBroadcast();
    }
}

public class MySecondReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", MySecondReceiver.class.getSimpleName() + " action:" + action);
        //截断广播
        //abortBroadcast();
    }
}

注册两个广播:

        <receiver
            android:name=".broadcast.MySecondReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcastdemo.ZY_TEST1103" />
            </intent-filter>
        </receiver>


        <receiver
            android:name=".broadcast.MyFirstReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcastdemo.ZY_TEST1103" />
            </intent-filter>
        </receiver>

发送普通广播:

    public void sendNormal(View view) {
        Intent intent = new Intent("com.example.broadcastdemo.ZY_TEST1103");
        sendBroadcast(intent);
    }

但是点击却怎么也收不到广播。前面已经说了,Android 8过后静态注册的广播是无法接受隐式广播的,而默认的情况下,我们发送的广播都是隐式广播。因此这里我们需要通过setPackage()方法,指定这条广播是发送到那个应用的,从而让他变成一条显示广播,否则静态注册的广播将无法接收到这条广播。

    public void sendNormal(View view) {
        Intent intent = new Intent("com.example.broadcastdemo.ZY_TEST1103");
        intent.setPackage("com.example.broadcastdemo");
        sendBroadcast(intent);
    }

LOG如下,发现两个广播接收器几乎同时接收到广播:

$ adb logcat -s zhangyu1103
--------- beginning of main
--------- beginning of system
--------- beginning of crash
11-02 16:28:06.240  5097  5097 D zhangyu1103: MySecondReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:28:06.244  5097  5097 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103

测试静态和动态同时注册的情况下

我们先改造一下广播,添加一个变量表示是否是动态注册还是静态注册:

public class MyFirstReceiver extends BroadcastReceiver {

    boolean flag = false; //false表示静态注册  true 表示动态注册

    public MyFirstReceiver() {
        this(false);
    }

    public MyFirstReceiver(boolean flag) {
        this.flag = flag;
        Log.d("zhangyu1103", "MyFirstReceiver init flag:" + flag+" "+this);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", MyFirstReceiver.class.getSimpleName() + " action:" + action);
        Log.d("zhangyu1103", "flag:" + flag+" "+this);
    }
}

页面启动的时候动态注册广播:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter intentFilter = new IntentFilter("com.example.broadcastdemo.ZY_TEST1103");
        registerReceiver(new MyFirstReceiver(true), intentFilter);
    }

点击发送普通广播两次,结果如下:

11-02 16:32:50.249  5333  5333 D zhangyu1103: MyFirstReceiver init flag:true com.example.broadcastdemo.broadcast.MyFirstReceiver@8466fcc


11-02 16:32:59.197  5333  5333 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:32:59.197  5333  5333 D zhangyu1103: flag:true com.example.broadcastdemo.broadcast.MyFirstReceiver@8466fcc

11-02 16:32:59.221  5333  5333 D zhangyu1103: MyFirstReceiver init flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@52ae90b
11-02 16:32:59.221  5333  5333 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:32:59.222  5333  5333 D zhangyu1103: flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@52ae90b

11-02 16:33:23.771  5333  5333 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:33:23.771  5333  5333 D zhangyu1103: flag:true com.example.broadcastdemo.broadcast.MyFirstReceiver@8466fcc

11-02 16:33:23.773  5333  5333 D zhangyu1103: MyFirstReceiver init flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@fee2800
11-02 16:33:23.773  5333  5333 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:33:23.773  5333  5333 D zhangyu1103: flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@fee2800

根据log可以看出:动态注册的广播和静态注册的广播都接收到了。但是动态注册的广播实例对象只有一个{8466fcc},静态注册的广播每次收到广播都会新建一个实例对象,比如{52ae90b}{fee2800}。

发送有序广播

第二个参数是跟权限有关的,这里传入null就可以。

    public void sendOrder(View view) {
        Intent intent = new Intent("com.example.broadcastdemo.ZY_TEST1103");
        intent.setPackage("com.example.broadcastdemo");
        sendOrderedBroadcast(intent, null);
    }

改变MyFirstReceiver的优先级。

        <receiver
            android:name=".broadcast.MyFirstReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcastdemo.ZY_TEST1103" />
            </intent-filter>
        </receiver>

在第一个接受的广播中休眠一秒:

public class MyFirstReceiver extends BroadcastReceiver {

    boolean flag = false; //false表示静态注册  true 表示动态注册

    public MyFirstReceiver() {
        this(false);
    }

    public MyFirstReceiver(boolean flag) {
        this.flag = flag;
        Log.d("zhangyu1103", "MyFirstReceiver init flag:" + flag+" "+this);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", MyFirstReceiver.class.getSimpleName() + " action:" + action);
        Log.d("zhangyu1103", "flag:" + flag+" "+this);
        // FIXME: 2020/11/3 做一点耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试结果:

11-02 16:45:47.736  5610  5610 D zhangyu1103: MyFirstReceiver init flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@2b63fc
11-02 16:45:47.736  5610  5610 D zhangyu1103: MyFirstReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:45:47.737  5610  5610 D zhangyu1103: flag:false com.example.broadcastdemo.broadcast.MyFirstReceiver@2b63fc
11-02 16:45:48.764  5610  5610 D zhangyu1103: MySecondReceiver init flag:false com.example.broadcastdemo.broadcast.MySecondReceiver@bd88a85
11-02 16:45:48.765  5610  5610 D zhangyu1103: MySecondReceiver action:com.example.broadcastdemo.ZY_TEST1103
11-02 16:45:48.765  5610  5610 D zhangyu1103: flag:false com.example.broadcastdemo.broadcast.MySecondReceiver@bd88a85

查看时间戳,MyFirstReceiver 先收到广播,MySecondReceiver 是在1秒后才收到广播。

截断广播发送

如果想截断广播的话,可以如下操作:

public class MyFirstReceiver extends BroadcastReceiver {

    boolean flag = false; //false表示静态注册  true 表示动态注册

    public MyFirstReceiver() {
        this(false);
    }

    public MyFirstReceiver(boolean flag) {
        this.flag = flag;
        Log.d("zhangyu1103", "MyFirstReceiver init flag:" + flag+" "+this);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d("zhangyu1103", MyFirstReceiver.class.getSimpleName() + " action:" + action);
        Log.d("zhangyu1103", "flag:" + flag+" "+this);
        // FIXME: 2020/11/3 做一点耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        abortBroadcast(); //截断广播
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值