Android之BroadcastReceiver使用

简介

BroadcastReceiver(广播接收器),这种组件本质上就是一个全局监听器,用于监听系统全局的广播消息。

BroadcastReceiver 用于接收程序(包括用户开发的程序和系统内建的程序)所发出的BroadcastIntent,与应用程序启动Activity、 Service相同的是,程序启动BroadcastReceiver也只需要两步。

  1. 创建需要启动的BroadcastReceiver的Intent。
  2. 调用 Context 的 sendBroadcast()或 sendOrderedBroadcast()方 法 来 启动指 定 的BroadcastReceiver

当应用程序发出一个Broadcast Intent 之后,所有匹配该 Intent 的 BroadcastReceiver 都有可能被启动。

与Activity、 Service具有完整的生命周期不同, BroadcastReceiver 本质上只是一个系统级的监听器——它专门负责监听各程序所发出的Broadcast。BroadcastReceiver属于系统级别的监听器,它拥有自己的进程,只要存在与之匹配的Intent被广播出来,BroadcastReceiver就会被激发。

由于 BroadcastReceiver 本质上属于一个监听器,因此实现 BroadcastReceiver 的方法也十分简单**,只要重写BroadcastReceiver 的 onReceive(Context context, Intent intent)方法即可。一旦实现了BroadcastReceiver,接下来就应该指定该 BroadcastReceiver 能匹配的 Intent,此时有两种方式。**

动态注册

  • 在代码中进行指定,调用BroadCastReceiver的Context的registerReceiver(BroadcastReceiver receiver, IntentFilter filter)方法指定
    例如监听系统网络变化
/**
 * 动态注册广播,监听
 */
public class DynamicBroadcastActivity extends AppCompatActivity {

    private NetWorkChangeReceiver netWorkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dynamic_broadcast);
        IntentFilter intentFilter = new IntentFilter();
        // android.net.conn.CONNECTIVITY_CHANGE 这个值,因为当网络状态发生变化时,系统发出的正是一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,也就是说我们的接收器想要监听什么广播,就在这里添加相应的action
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        // IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
        netWorkChangeReceiver = new NetWorkChangeReceiver();
        registerReceiver(netWorkChangeReceiver, intentFilter);
    }

    class NetWorkChangeReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "network changed", Toast.LENGTH_SHORT).show();
        }
    }

静态注册

主要是为了程序在未启动的时候也能接收广播。

在AndroidManifet.xml文件中配置。例如如下代码:

        <receiver
            android:name=".broadcastReceiver.MyStandardBroadcastReceiver"
            android:exported="true"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.example.androidlearn.standardBroadcast"></action>
            </intent-filter>
        </receiver>

在配置<receiver…/>元素时可指定如下常用属性。

  • name: 指定该BroadcastReceiver的实现类名
  • exported: 指定该BroadcastReceiver是否能接收其他App发出的广播。如果在配置该组件时配置了<intent-filter.>子元素,那么该属性默认为true。
  • enabled:是否启用这个广播接收器
  • label: 指定该 BroadcastReceiver 的标签。
  • permission: 指定激发该 BroadcastReceiver 所需要的权限。
  • process: 指定该BroadcastReceiver所处的进程,该广播接收器默认处于该 App所在的进程中。

实际上,Android的四大组件都可通过该属性指定进程。每次系统Broadcast事件发生后,系统都会创建对应的BroadcastReceiver实例,并自动触发它的onReceive()方法, onReceive()方法执行完后, BroadcastReceiver实例就会被销毁。

注意

  • 如果BroadcastReceiver的onReceive()方法不能在10秒内执行完成, Android会认为该程序无响应。所以不要在BroadcastReceiver的 onReceive()方法里执行一些耗时的操作;否则会弹出ANR(Application No Response) 对话框。

  • 如果BroadcastReceiver所在的进程结束了,虽然该进程内还有用户启动的新线程,但由于该进程内不包含任何活动组件,因此系统可能在内存紧张时优先结束该进程。这样就可能导致BroadcastReceiver 启动的子线程不能执行完成。

广播

Broadcast 被分为如下两种。

  • Normal Broadcast (普通广播): Normal Broadcast 是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高。但缺点是接收者不能将处理结果传递给下一个接收者,并且无法终止Broadcast Intent 的传播。
  • Ordered Broadcast (有序广播): Ordered Broadcast 的接收者将按预先声明的优先级依次接收Broadcast。比如A的级别高于B、B的级别高于C,那么Broadcast先传给A,再传给B,最后传给C。优先级别声明在<intent-filter.>元素的android:priority属性中,数越大优先级别越高,取值范围为-1000-1000,也可以调用IntentFilter 对象的setPriority0设置优先级别。Ordered Broadcast 接收者可以终止 Broadcast Intent 的传播, Broadcast Intent 的传播旦终止,后面的接收者就无法接收到Broadcast。另外, Ordered Broadcast的接收者可以将数据传递给下一个接收者,比如A得到Broadcast后,可以往它的结果对象中存入数据,当Broadcast传给B时,B可以从A的结果对象中得到A存入的数据。

Context提供的如下两个方法用于发送广播。

  • sendBroadcast(): 发送 Normal Broadcast
  • sendOrderedBroadcast(): 送 Ordered Broadcast

Android 8 对 BroadcastReceiver 进行了改进,静态注册的接收器无法接收到隐式广播。 静态注册广播 Android 8 要求启动 BroadcastReceiver 的 Intent 必须是显式 Intent——就像启动 Service 的 Intent 一样,要么直接设置 BroadcastReceiver 类名;要么通过 Action 和 package 来设置显式Intent。,发送的时候需要设置package或者componentName,指定此广播是发送给哪个应用程序,让其变成显式广播(总之还是尽量多用动态注册)

1.发送标准广播

1.1 新建了继承BroadCastReceiver

android studio 右键 New -> Other -> Broadcast Receiver
在这里插入图片描述
在这里插入图片描述
这样自动在androidManifest.xml中注册。
添加相应的action

		<receiver
            android:name=".broadcastReceiver.MyStandardBroadcastReceiver"
            android:exported="true"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.example.androidlearn.standardBroadcast"></action>
            </intent-filter>
        </receiver>

BroadcastReceiver代码如下:

public class MyStandardBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "发送自定义标准广播", Toast.LENGTH_SHORT).show();
    }
}

1.2 发送广播

使用sendBroadcast发送广播

public class StandardBroadcastActivity extends AppCompatActivity {

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

        findViewById(R.id.standard_broadcast_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.androidlearn.standardBroadcast");

                intent.setComponent(new ComponentName(getPackageName(),"com.example.androidlearn.broadcastReceiver.MyStandardBroadcastReceiver"));
                sendBroadcast(intent);
            }
        });
    }
}

2. 发送有序广播

设置两个广播接收器MyReceiver1和MyReceiver2的优先级分别设置为200和100

        <receiver
            android:name=".broadcastReceiver.MyReceiver1"
            android:enabled="true"
            android:exported="true" >
            <intent-filter android:priority="200">
                <action android:name="android.intent.action.SORT_BROADCAST" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".broadcastReceiver.MyReceiver2"
            android:enabled="true"
            android:exported="true" >
            <intent-filter android:priority="100">
                <action android:name="android.intent.action.SORT_BROADCAST" />
            </intent-filter>
        </receiver>

MyReceiver1代码如下:

public class MyReceiver1 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "接收器1", Toast.LENGTH_SHORT).show();
        abortBroadcast(); // 取消Broadcast的继续传播
    }
}

MyReceiver2代码如下:

public class MyReceiver2 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "接收器2", Toast.LENGTH_SHORT).show();

    }
}
``

Activity代码如下:

```java
public class SortBroadcastActivity extends AppCompatActivity {

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

        findViewById(R.id.send_sort_broadcast_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("android.intent.action.SORT_BROADCAST");
                intent.setPackage(getPackageName());
                sendOrderedBroadcast(intent, null);
            }
        });
    }
}

3.发送本地广播

前面我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送 各种垃圾广播。

为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。

本地广播的用法并不复杂,主要就是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。下面我们就通过具体的实例来尝试一下它的用法,修改MainActivity中的代码,如下所示:


import com.example.androidlearn.R;

public class LocalBroadCastActivity extends AppCompatActivity {

    private IntentFilter intentFilter;

    private LocalReceiver localReceiver;

    private LocalBroadcastManager localBroadcastManager;


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

        localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取实例
        Button button = (Button) findViewById(R.id.local_broadcast_btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent); // 发送本地广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver, intentFilter); // 注册本地广播监听器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        localBroadcastManager.unregisterReceiver(localReceiver);
    }


    class LocalReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }

    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值