Android组件(三)Broadcast


注:本文代码部分参考《第一行代码 Android》第二版

1.简述Broadcast

Broadcast 是 Android 四大组件之一,是一种广泛运用在应用程序之间异步传输信息的机制。Broadcast 本质上是一个Intent 对象,差别在于 Broadcast 可以被多个 BroadcastReceiver 处理。BroadcastReceiver 是一个全局监听器,通过它的 onReceive() 可以过滤用户想要的广播,进而进行其它操作。广播的发送者和接收者事先是不需要知道对方的存在的。这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。

2.广播

2.1 标准广播(Normal broadcasts)

标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此它们之间没有任何先后顺序可言,receivers(接收器)的执行顺序不确定。这种广播的效率会比较高,但同时也意味着它是无法被截断的。

2.2 有序广播(Ordered broadcasts)

有序广播是一种同步执行的广播,在广播发出后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的可以先接收到消息,并且靠前的广播接收器可以截断正在传递的广播,这样后面的接收器会收不到这条广播消息 。优先级别在intent-filter中的priority中声明,-1000到1000之间,值越大优先级越高,同一优先级依然是随机接收顺序。

2.3 粘性广播(Sticky Broadcast)

粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如果onReceive()方法执行时间太长,超过10秒的时候系统会将这个广播置为可以干掉的candidate,一旦系统资源不够的时候,就会干掉这个广播而让它不执行。该广播用sendStickyBroadcast发送。

3.动态注册

3.1 什么是动态注册

动态注册就是利用代码注册,动态注册的广播接收器可以自由的控制注册和取消,有很大的灵活性。但是只能在程序启动之后才能收到广播,广播接收器的注销是在onDestroy()方法中的。所以广播接收器的生命周期是和当前活动的生命周期一样。

3.2 动态注册步骤

(1)实例化自定义的广播接收器。
(2)创建IntentFilter实例。
(3)调用IntentFilter实例的addAction()方法添加监听的广播类型。
(4)最后调用Context的registerReceiver(BroadcastReceiver,IntentFilter)动态的注册广播

3.3 动态注册监听网络变化

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter =new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    class NetworkChangeReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"network changes",Toast.LENGTH_SHORT).show();
        }
    }
}

在MainActivity中定义一个内部类NetworkChangeReceiver,这个类继承自BroadcastReceiver,并重写了父类的onReceive()方法。当网络状态发生变化时,onReceive()方法就会得到执行。
具体过程:在onCreate()方法中先创建一个intentFilter实例,并给它添加一个值为android.net.conn.CONNECTIVITY_CHANGE的action。当网络发生变化,系统发出的值为android.net.conn.CONNECTIVITY_CHANGE的广播正是广播接收器要监听的。接下来创建NetworkChangeReceiver
实例,调用registerReceiver()方法注册,将NetworkChangeReceiver和IntentFilter的实例传入,这样NetworkChangeReceiver就收到值为android.net.conn.CONNECTIVITY_CHANGE的广播,实现广播接听。最后动态广播接收器使用unregisterReceiver()方法取消注册。
注意:
1)发送广播之前,要先注册,不然根本没有接收者匹配,不注册接收者虽然不会出现任何错误或警告,但是只发送一个没有任何接收者的广播播毫无意义。
2)Android保护用户设备的安全与隐私,要求:如果程序需要进行一些对用户来说比较敏感的操作,就必须在配置文件中声明权限。即在AndroidManifest.xml文件中加入

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

4.静态注册

4.1 什么是静态注册

静态注册就是利用XML来注册。当我们需要一直接收某种广播时,可以使用静态注册方式。静态注册的程序,无论该程序是否启动,都会当广播到来时接收,并处理。而动态注册的程序只有在程序运行时才会收到广播消息,程序不运行了,它就收不到了。
可以使用Android Studio 中的快捷方法来创建广播接收器。
右击包名——New——Other——BroadcastReceiver

4.2 静态注册实现开机启动

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"Boot Complete",Toast.LENGTH_LONG).show();
    }  
} 

在创建好的广播接收器中修改代码,在onReceive()方法中使用toast弹出一段提示信息。这时AndroidManifest.xml中的标签内出现了一个新的标签

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

由于Android系统启动完成后会打出一条值为android.intent.action.BOOT_COMPLETED的广播,因此添加对应action,

        <receiver
            android:name=".MyReceiver"
            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"/>

5.发送标准广播

新建一个接收器MyBroadcastReceiver,当MyBroadcastReceiver收到自定义的广播时,就会弹出"received in MyBroadcastReceiver"的提示。

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_LONG).show();
    }  
} 

修改AndroidManifest.xml文件,指定MyBroadcastReceive接收广播

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

在布局文件中添加一个按钮,用于发送广播的触发点

            <Button
                android:id="@+id/button_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/login"
                />

修改MainActivity代码,在按钮的点击事件里加入了发送自定义广播的逻辑。先构建一个intent对象,并把要发送的广播的值传入,然后调用了Context的sendBroadcast()方法将广播发送出去,这样所有监听com.example.broadcasttest.MY_BROADCAST这条广播的广播接收器都会收到消息。这时发出的就是一条标准广播。

        Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                Intent intent =new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendBroadcast(intent);
                        
            }
        });

6.发送有序广播

在标准广播的基础上,修改MainAcivity中的代码,将 sendBroadcast(intent);改为sendOrderedBroadcast(intent,null);
前一个参数为intent,后一个参数为权限相关的字符串。

        Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                Intent intent =new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendOrderedBroadcast(intent,null);
                        
            }
        });

在注册时进行设定广播接收器的先后顺序,修改AndroidManifest.xml,通过android:priority属性给广播接收器设置优先级。

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

若要选择是否允许广播继续传递,需要在onReceive()方法中调用abortBroadcast(),表示将广播截断,后面的广播接收器无法收到这条广播。

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"received in MyBroadcastReceiver",Toast.LENGTH_LONG).show();
    abortBroadcast();
    }  
} 

7.发送本地广播

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager=LocalBroadcastManager.getInstance(this); //获取实例
        Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                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();
        }
    }
}

代码部分与动态广播接收器类似,区别在于通过LocalBroadcastManager的getInstance()方法得到一个实例,然后注册广播接收器时调用localBroadcastManager的registerReceiver()方法,发送时调用 localBroadcastManager的sendBroadcast()方法。
本地广播特点:
1)本地广播只会在程序内传播。可以避免数据泄漏。
2)无法使用静态注册方式接收。因为静态注册是为了让程序在未启动难过的情况下也能接收广播,而发送本地广播时,程序一定是已经启动了。
3)发送本地广播会比发送系统全局广播更高效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rpk712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值