第四章(广播机制Broadcast简介)

广播机制简介

Adroid中的广播主要分为两种类型:标准广播和有序广播。

标准广播:

标准广播是一种完全异步执行的广播,在广播发出以后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此它们之间没有图呢he先后顺序可言,这种广播效率会比较高,但也以为着它是无法被截断的

有序广播

有序广播是一种同步执行的广播,在广播发出以后,同一时刻只会有一个广播接收器能接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就优先接收到广播消息,并且前面的广播接收器可以截断正在传递的广播,后面的广播接收器就不能接收到广播消息了。

接收系统广播

Android内置了很多系统级别的广播,我们可以在程序中监听这些广播来得到系统的状态信息,比如,手机开机后系统会发送一条广播,电池没电了系统也会发送一条广播。如果想接收到这些广播就需要使用广播接收器。

注册方式

广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能接收到该广播,并在内部处理相应的逻辑。注册广播方式一般有两种,第一种实在代码中注册,第二种实在AndroidManifest.xml中注册,前者成为动态注册,后者成为静态注册
下面举几个例子

  • 动态注册监听网络变化,新建项目BroadcastTest1

如何建一个广播接收器?只需建一个类继承BroadcastReceiver并重写父类的onReceiver方法就行了,当有广播到来时onReceiver方法就会得到执行

   class NetWorkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
        }
    }

这个类可以写在Activity的内部,也可以另外建一个类

  1. 监听网络状态变化
public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetWorkChangeReceiver receiver;

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


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

    
    class NetWorkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
        }
    }
}

当系统网络状态发生变化的时候,系统就会发出一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,所以我们在IntentFilter中添加相应的action,然后调用registReceiver方法进行注册,传入NetWorkChangeReceiver和IntentFilter的实例,这样就实现了监听网络变化的功能。最后记得动态注册的广播接收器一定要取消才行,即在onDestroy中通过调用unregisterReceiver方法来实现


image
  1. 监听网络是否可用
    我们创建一个SecondActivity,并创建一个NetWorkChangeReceiver继承BroadcastReceiver并重写onReceive方法
public class SecondActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver netWorkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        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) {
            ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            //getSystemService根据名字获取一个系统级别的服务类
            NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
            if(networkInfo!=null&&networkInfo.isAvailable()){
                Toast.makeText(context,"网络可用",Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(context,"网络不可用",Toast.LENGTH_SHORT).show();
            }

        }
    }
}

在onReceive方法中首先通过getSystemService获得ConnectivityManager的实例,这是四专门用于管理网络连接的,然后调用它的getActiveNetworkInfo方法获得一个NetworkInfo的实例,最后调用NetworkInfo的isAvailable方法判断当前是否有网络,通过Toast提示。
这里访问系统的网络状态是要声明权限的


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

我们点击NETWORK_CHANGE_DETAILS按钮,启动SecondACtivity,打开或关闭数据服务就能看到Toast提示


image
  • 静态注册实现开机启动监听(系统开机后会发送一条广播)

动态注册的广播接收器可以自由地注册和注销,很灵活,但是它有个缺点就是必须 要把程序启动之后才能实现监听,因为注册逻辑是卸载onCreate方法中的。
使用静态注册的方式能让程序在未启动的状态下实现监听广播。下面看怎么使用

  1. 新建一个广播接收器名为BootCompletReceiver并将Exported和Enabled属性勾选。Exported属性表示是否允许这个广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器


    image

public class BootCompletReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"开机完成",Toast.LENGTH_SHORT).show();
    }
}

  1. 静态注册的广播接收器一定要在AndroidManifest.xml文件中注册才能使用,但由于我们是使用AS自带的快捷方式创建的广播接收器,所以它自动帮我们将这一步完成了
     <receiver
            android:name=".BootCompletReceiver"
            android:enabled="true"
            android:exported="true">
            </receiver>
      
  1. 所有的静态广播接收器都要在<receiver>标签内进行注册,name用来制定是注册哪一个广播接收器,enabled和exported是根据我们刚才勾选的状态自动生成的。
    由于系统启动后会发送一条值为android.intent.action.BOOT_COMPLETED的广播,所以我们要在<intent-filter>标签中添加相应的action

       <receiver
            android:name=".BootCompletReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
  1. 添加相应的权限,监听系统开机广播是需要声明权限的
 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

这样就能实现开机程序监听开机广播了


image
  • 发送自定义广播

前面介绍了广播分为两种:标准广播和有序广播

发送自定义标准广播,新建MyBroadcastReceiver项目
  1. 我们新建一个自定义的广播接收器

public class MyBroadcastReceiver extends BroadcastReceiver {

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

  1. 在布局里面添加一个Button,点击这个Button就会发送我们自己定义的广播
    public void sendbroadcast(View view) {
        Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
        sendBroadcast(intent);
    
    }
    

Intent中传入的是一条Action值,然后调用sendBroadcast方法将intent传进去,当然现在还是不能监听广播的,我们还需要在清单文件中配置一下

  1. 修改AndroidManifest.xml

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

这样我们的点击Button就会发出一条我们自定义的广播并且能接收到这条广播了

发送自定义的有序广播
  1. 发送有序广播非常简单,只需要将sendBroadcast改成sendOrderedBroadcast并传入两个参数
public class MainActivity extends AppCompatActivity {

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

    public void sendbroadcast(View view) {
        Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
        //sendBroadcast(intent);
        sendOrderedBroadcast(intent, null);
    }
}

第一个参数是Intent不用解释,另一个参数是一个与权限相关的字符串官方解释是:String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.一般情况下传入null就可以了,除特殊情况。

  1. 成功发送有序广播后我们再试图去别的程序里面截断这条广播,使发出这条广播的程序无法接收到这条广播
    在上面动态注册监听网络变化BroadcastTest1项目里面创建一个AnotherBroadcastReceiver
public class AnotherBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"在Broadcasttest1中接收到了MyBroadcastReceiver发出的广播",Toast.LENGTH_SHORT).show();
        abortBroadcast();//截断这条广播
    }
}

截断广播非常简单,只需要在BroadcastReceiver中调用abortBroadcast()方法就行了

  1. 然后修改BroadcastTest1项目中的AndroidManifest.xml文件
     <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter>
                <action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
            </intent-filter>
        </receiver>
  1. 要想截断这条广播那么我们就必须保证BroadcastTest1程序优先于MyBroadcastReceiver程序接收到MyBroadcastReceiver程序发送的广播,并截断这样MyBroadcastReceiver程序就不会接收到它自己发送的广播了。怎样做呢?其实只需要设置一个优先级就可以了,添加android:priority="100",设置成一百就可以了
     <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter 
            android:priority="1000">
                <action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
            </intent-filter>
        </receiver>
        

这样BroadcastTest1程序就能接收到MyBroadcastReceiver程序发送过来的广播了,并且能截断它。


image
  • 使用本地广播

上面讲的发送和接收的都属于全局广播,即发出的广播可以被其他任何应用程序接收到,并且也可以接受来自其他程序的广播,这样就不够安全,为了解决这个安全问题,Android引入了一套本地的广播机制,使用这个机制程序发出的广播只能在程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样安全性问题就不存在了。
主要是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法,看例子:

package com.example.houchongmu.mybroadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class LocalBroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalBroadcast localBroadcast;
private LocalBroadcastManager localBroadcastManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_local_broadcast);
        intentFilter=new IntentFilter();
        localBroadcast=new LocalBroadcast();
        localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取LocalBroadcastManager的实例
        intentFilter.addAction("com.example.localbroadcast");
        localBroadcastManager.registerReceiver(localBroadcast,intentFilter);
    }
    
    public void send_localbroadcast(View view){
        Intent intent=new Intent("com.example.localbroadcast");
        localBroadcastManager.sendBroadcast(intent);
    }
    
    class LocalBroadcast extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"接收到本地广播",Toast.LENGTH_SHORT).show();
        }
    }

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

上面的代码很容易理解就不过多解释了


image

关于广播机制就暂时讲到这里,以后学习到新的知识再进行补充。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 【Android 广播】 BroadcastReceiver简介 BroadcastReceiver(广播接收器)...
    Rtia阅读 3,382评论 1 17
  • 1.引言 在《第四章 Android 四大应用组件》中,简单介绍了下四大组件的成员,属性,生命周期等。这里主要是介...
    忆念成风阅读 1,457评论 1 10
  • 在一个IP网络范围中,最大的ip地址是被保留用作广播地址来使用的,比如某个IP范围是192.168.0.xxx,子...
    小徐andorid阅读 1,329评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,597评论 18 139
  • 世俗的人只有在阳光照耀下,才能昂首前行。遇到黑暗就变得畏缩不前。多少人为了短暂的阳光,宁愿把自己装在气泡中,对别人...
    凯罗阅读 265评论 0 0