美文网首页
Broadcast Receiver 的使用

Broadcast Receiver 的使用

作者: 做梦枯岛醒 | 来源:发表于2019-02-01 16:47 被阅读5次

同步发表:https://blog.surine.cn/2019/02/01/Broadcast-Receiver-的使用/

最近在复习Android的知识,从最基础的开始深入探究,初学Android的时候,四大组件学的很茫然,其实最多的用到的也就是Activity,其他的接触的都不多。
这里我们探究一下广播机制。

1.动态注册

我们用As新建一个接收器。


新建

这里我们可以使用它的快捷新建的方式,右键包名新建一个Other,选择Broadcast Receiver即可快速新建接收器。

我们输入类名,下面两个默认选中即可,其中exported选中为true,标识允许其他APP调用该组件,enabled标识是否可以被系统实例化,选中也为true,不必多探究。

确认之后,就可以看到系统为我们生成了一段代码

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //继承了BroadcastReceiver ,需要实现其中的接受方法。
    }
}

同时我们的manifest文件中也出现了注册,注意一下四大组件都需要在manifest中定义哦。

    <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" />

接收器中我们写一个Log,修改如下

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
            //这里我封装了一下log,你依然可以使用原生的log来打印
             Logs.d("收到!");
    }
}

这样我们的接收器就写好了。
我们在Activity中注册接收器,首先生成接收器和过滤器对象,接收器是用于注册的,那么过滤器是用来干嘛的?

机智如你,当然是过滤广播的,举个例子,学校的广播分年级宣布事情,你是高一的,你就不需要管高二的事情,而只需要过滤出高一的事情即可,一会你就会看到IntentFilter 设置所关心的事情的方法。

private MyReceiver myReceiver = new MyReceiver();
    private IntentFilter mIntentFilter = new IntentFilter();
    

接下来注册广播,在onCreate()里设置你的关心并且注册。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);   
        mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        //注册广播接收器
        registerReceiver(myReceiver,mIntentFilter);
    }

可以看到,addAction()用于设置关心,而我设置的android.net.conn.CONNECTIVITY_CHANGE属性是代表了网络连接状态,所以你自会明白,我这个接收器,专门接受网络变化的广播。

最后要是离开这个页面,我们还需要解注册

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //解注册
        unregisterReceiver(myReceiver);
    }

运行之后,界面没有变化,而当我们点击数据或者无线网关掉网络,我们的Log就会出现打印。

2. 静态注册

上面部分叫做动态注册,因为必须要在页面中使用才能看出来效果,那么还有一个静态注册,场景也很广泛,不用打开APP即可实现。
比如我们常见的开机自启动。
当系统开机的时候,发送一条广播。
注册开机广播接收的App在接收器中即可收到这条广播,然后在其中的逻辑中运行它的服务,即可实现开机自启动。
但目前很多国产手机都右禁用开机自启动,所以这个过程要更为复杂一些。

依然用刚才的接收器,里面的内容改成Toast(这里依然是我封装的,请自己选择合适的方式使用)

 @Override
    public void onReceive(Context context, Intent intent) {
        Toasts("开机啦!");
    }

然后给系统添加开机自启动权限。

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

接着又修改了一下我们刚才注册的receiver,里面添加了<intent-filter>标签,这个看起来就异常的简单啦。
因为我们刚才学到的动态注册就是用了这个过滤器,这里,只不过是在xml中的写法,比如下面的action标签,添加的android.intent.action.BOOT_COMPLETED属性,都是我们刚才降到过的,其中BOOT_COMPLETED标识开机完成,类似的属性还有重启等等。

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

这样我们只需要一个接收器和xml这一段内容即可,刚才写的动态注册都要删掉了。
这样我们关机后,再开机即可收到Toast,当然部分手机可能因为自动禁用开机自启动权限效果有所不同,请自行探究。

3.自定义广播

有了刚才的经验,我们就可以发送自定义广播了,无非是过滤器所关注的广播改成你所广播的内容,(接收器目前是开机Toast提示,该与不该都可),主要是看xml中,

<receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="susu.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

我继续在原代码上添加了新的一行,并且让这个关注点叫做susu.MY_BROADCAST,名字随意,一会我们发送的时候对应起来即可。

MainActivity中添加了一个按钮,点击这个按钮的时候即可发送广播,可以看到这里的广播就是我们刚才注册的那个。

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

我们看一下我们调用的这个intent构造吧,(按住Ctrl,单击new Intent的Intent)

// @param action The Intent action, such as ACTION_VIEW.
    public Intent(String action) {
        setAction(action);
    }

可以看到@param已做出解释,action是intent action,也就是我们前面一直提到的action,这样就全部对应起来啦。

运行起来,点击按钮,会弹出相应提示。

4. 小结

这里总结一下。

  1. 广播注册主要分为静态注册和动态注册,其中值得我们关注的就是过滤器,通过设置过滤的action(动作),接受自己所感兴趣的事情。
  2. 上述例子中,开机自启动的实现如果不能达成效果也很正常,由于API的变更或者厂商的定制总会出现一些各种各样的问题。
    3.前面提起过,广播是全局的,你写的App发送广播,别的App也可以收到(如果注册了的话),别的App发你的也可以收到,这里你可以写两个Demo尝试一下。
  3. 如果你用的Android8.0及以上的系统,可能上述自定义广播栗子无法实现预期效果,主要是因为Android API的修改,Android系统电量系统优化导致的。
    你可以给intent增加了一个内容,修改如下
 Intent intent = new Intent("susu.MY_BROADCAST");
                intent.setComponent(new ComponentName("cn.surine.statusbardemo","cn.surine.statusbardemo.MyReceiver"));
                sendBroadcast(intent);

我们可以看到设置了一个Component,第一个参数是包名,第二个参数是MyReceiver即接收器的路径。

酱紫,就可以收到啦!
你以为结束了?
不可能!!!

5.有序广播

What?怎么又来,有序广播是什么。
有序广播是按照顺序来的,举个栗子,小红,小张,小明都要接受老师的同一条命令。
有两种形式,第一种,老师把他们三个找来,一下子传达,这个方式叫做标准广播,上面我们写过的都是标准广播
第二种,老师把小红找来,传达之后让小红传给小张,小张传给小明,但这里就有问题了,为什么是先传给小红而不是小明,小张会不会不给小明传达?等等等等问题。
这种方式就是有序广播,对应的问题就是广播优先级广播截断

那么现在我们实现有序广播。

sendOrderedBroadcast(intent,null);

好本次教程到此结束。
What???

因为太简单了,刚才我们写的sendBroadcast方法你还记得吧,别告诉我你忘了,你要是忘了就代表你一直在抄我的代码而没有自己写。

那个方法传了一个intent进去,这里sendOrderedBroadcast也传了intent,第二个参数为null是receiverPermission,暂且不用管。

这样就可以了,这就是有序广播。

但是有序广播刚才提到了两个问题,优先级和截断。
优先级在哪里设置?
答案就是注册这里,设置优先级100,保证先收到。

<receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter android:priority="100">
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="susu.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

确保它第一个收到之后,我们可以在它的接收器方法中增加一个截断。

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

这样 下一个,比如说小明,就收不到广播了,是不是很霸道的样子。
这里我就一个Demo,我也木有演示效果,你可以自行演示。

6. 本地广播

刚才我们上面全部的广播,我都提到过,全局,全局意味着什么,别的App也可以收到我们的广播,万一我们的广播action恰好被别人知道了(虽然几率很小),那他是不是可以不停的发送垃圾广播来干扰我们的app正常运行,或者我们发送的关键数据,会不会泄露到其他App中?

这系列问题,都急需一个方法来处理,这就是本地广播。
下面我们来实现。

依然是MyReceive,我们看一下新代码,自行处理接受到信息的内容。

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
          Toasts.show("接收到广播");
    }
}

xml改成这样。

   <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true" />

所有的操作都将在Java里面匹配。

package cn.surine.statusbardemo;

import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    
    private Button button;
    private LocalBroadcastManager localBroadcaseManager;
    private MyReceiver myReceiver = new MyReceiver();
    private IntentFilter intentFilter = new IntentFilter();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取LocalBroadcastManager实例
        localBroadcaseManager = LocalBroadcastManager.getInstance(this);
        //添加过滤器
        intentFilter.addAction("susu.MY_BROADCAST");
        //注册
        localBroadcaseManager.registerReceiver(myReceiver,intentFilter);

        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //发送广播
                Intent intent = new Intent("susu.MY_BROADCAST");
                intent.setComponent(new ComponentName("cn.surine.statusbardemo","cn.surine.statusbardemo.MyReceiver"));
                sendBroadcast(intent);
            }
        });

    }


    //解注册
    @Override
    protected void onDestroy() {
        super.onDestroy();
        localBroadcaseManager.unregisterReceiver(myReceiver);
    }
}

这里是发送的全部的代码,可以看到似曾相识,因为这个和动态注册是一样的,只不过由LocalBroadcastManager一手接管了注册,解注册等等工作。

可能你有疑问,动态和本地都差不多,为啥要区分,
主要是是因为动态广播在其他App可以发送,本地广播就局限于App内。

7 .总结

又是总结。
这回真的是总结了。
在这里开始挖坑,有的童鞋可能用过EventBus,它的形式跟广播类似,不用在乎是否收到,只要订阅了接收器,就可以收到接受的信息,不过也有所不同。

挖好了坑,我们不知道何年何月才能探究出来。
总之,要学的东西有很多,继续加油!

相关文章

  • Notification和NotificationManager

    使用Notifaction和NotifactionManager的目的 Broadcast Receiver组件并...

  • Broadcast Receiver 的使用

    同步发表:https://blog.surine.cn/2019/02/01/Broadcast-Receiver...

  • 保护本应用发送的broadcast和receiver

    使用动态broadcast receiver存在一个问题,即系统中的任何应用均可以监听并触发你的receiver,...

  • Android BroadcastReceiver详解

    Broadcast Receiver是什么 Broadcast Receiver是四大组件之一,是一种广泛运用在应...

  • Activity之生命周期

    Android四大组件有Activity,Service,Broadcast Receiver,Broadcast...

  • Broadcast Receiver

    一、广播 1.广播定义 Broadcast Receiver是一种广泛运用的在程序之间传输信息的机制,androi...

  • Broadcast Receiver

    广播的定义 四大组件之一,是安卓应用程序之间传递信息的机制。我们要发送的广播内容是一个Intent,这个Inten...

  • Broadcast Receiver

    广播广泛运用于应用程序之间传输信息(进程间通信)的机制,而BroadcastReceiver是对发送出来的广播进行...

  • Broadcast Receiver

    一.广播 1.在Android中,Broadcast在应用程序之间传输信息的机制,我们发送的广播内容是一个Inte...

  • Broadcast Receiver

    广播的两种类型 标准广播(Normal broadcasts) : 是一种完全异步执行的广播,在广播发出后,所有...

网友评论

      本文标题:Broadcast Receiver 的使用

      本文链接:https://www.haomeiwen.com/subject/jsrdsqtx.html