Android四大组件之Broadcast

谨以此文送个我最爱的龙哥,希望对他有帮助。顺便借此机会温故知新

Broadcast虽然是四大组件,但是感觉用到的挺少的,感觉项目中我只用到了判断网络状态和判断电量
下面整理资料,主要来源于郭霖的《第一行代码》第二版和网络


广播分为
1.标准广播
是一种完全异步执行的广播,在广播发出去的之后,所有的广播接收器在同一时间接收到了广播,因此他们之间没有任何先后顺序可言,这种广播的效率会比较高,但是同时一位置他无法被截断。工作流程如下图所示
这里写图片描述
2.有序广播
是一种同步执行的广播,在广播发出去以后,同一时间只有一个广播接收器可以接收到此条广播,当这个广播接收器中的判断逻辑走完之后,广播才会继续传播,所以此时的广播接收器是有先后顺序的,优先级高的广播接收器会先收到广播,并且前面的广播接收器还能拦截后边的广播接收器,这样后边的广播接收器就无法收到广播消息了,工作流程如图所示
这里写图片描述

了解了广播的基本分类,有序广播,无序广播之后,我们来进行一些简单的demo


接收系统广播
android内置很多系统级别的广播,我们可以在应用中通过监听这些广播来得到各种系统的状态信息。比如手机开机后会发出一条广播,电池电量发生变化时候会发生广播,时间和时区发生变化的时候会发出一条广播,等等。如果想要接收到这些广播,就需要使用广播接收器,
具体系统广播可检测到什么,见附件1。

注册广播一般分为:
在代码中注册:动态注册
在清单配置文件中注册,静态注册

1.动态注册监听网络变化
新建一个内部类,让他继承BroadcastReceiver,并重写父类的onReceiver()方法
这样当广播到来时,onReceover()方法就会执行
具体的逻辑就在这个方法中进行

public class MainActivity extends AppCompatActivity {
    IntentFilter intentFilter;
    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();
        }
    }


}

效果图
这里写图片描述
动态注册的关闭,需要取消注册,这里,我们实在onDestory()中调用unregisterReceiver()来实现

2.静态注册实现开机启动
动态注册的广播接收器可以自由的控制注册和注销,在灵活性方面有很大的优势,但是他存在一个缺点,即必须在程序启动之后才能接收到广播,因为注册的逻辑卸载oncreate()中,
如果想要在程序未启动的情况下就能接收到广播,那就需要静态注册
这里我们准备让程序接收一条开机关闭,用快捷方式在as中注册广播
创建广播BootCompleteReceiver

public class BootCompleteReceiver extends BroadcastReceiver {

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

可以在配置文件中找到静态注册的广播

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

我们加入interFilter标签,并且添加先用action

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

这里写图片描述

到目前为止,我们在广播接收器onReceiver()方法中都只是简单的用toast提示了一段文本信息,当你真正的在项目中用到它的时候,就可能在里边编写自己的逻辑。需要注意的事,不要再receiver()方法中添加过多的逻辑,或者进行任何的好事操作,因为在广播接收器中是不允许开线程的,当onReceiver方法运行了较长时间而没有结束的时候,程序就会报错,因此广播接收器更多的实质扮演一种打程序其他组件的角色,比如创建一个状态栏通知,或者开启一个服务,

3.发送自定义广播
3.1发送标准广播
首先创建一个广播接收器

public class MyBroadcastReceiver extends BroadcastReceiver {

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

在配置文件中设置这个广播接收器

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

可以看到让MyBroadcastReceiver接收一个广播,值为“fxr”。我们需要发出一个值为
fxr的广播
Activity中的代码

public class SecondActivity extends AppCompatActivity {
Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        button=(Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent("fxr");
                sendBroadcast(intent);
            }
        });

    }
}

这里写图片描述

3.2发送有序广播
广播是一种跨进程的通信方式,这一点从前面接收系统广播的时候我们就可以看出来,因此我们app发出的广播,其他app也可以就收到,为了验证这一点,我们需要在创建一个项目broadcasetest2
然后直接创建一个广播

public class AnotherBroadcaseReceiver extends BroadcastReceiver {

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

同样的是接收“fxr”

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

这时候我们运行下这个demo2,然后运行下demo1,此时保证demo2在后台存在
我们点击demo的按钮,就会弹出来2个toast
这里写图片描述
这就证明,我们程序发出来的广播,别的程序也能接收到,
不过,目前为止,我们都是发送的标准广播,我们尝试下发送有序广播,修改BroadcastTest项目(demo1)中的代码

 button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent("fxr");
                sendOrderedBroadcast(intent,null);
            }
        });

可以看到,发送有序广播只需要改动一行代码,将sendBroadcast()方法改成sendOrderBroadcast()方法。
sendOrderBroadcast()方法接收两个参数,第一个参数仍然是Intent,第二个参数是一个和权限相关的字符换,我们这里传入null就好,现在我们点击按钮,这就很尴尬,2个广播的接收器的toast还是都弹出,看上去和标准广播没什么区别,我们可以设置优先级,给广播接收器设置先后顺序,我们给demo2 的配置文件中进行修改

<receiver
            android:name=".AnotherBroadcaseReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action
                    android:name="fxr"
                    />
            </intent-filter>
        </receiver>

可以看到,我们通过android:priority属性给广播设置了优先级,优先级比较高的可以先接收到关闭,我们吧demo2设置为100,我们在运行测试下
这里写图片描述
可以先看到another在显示另外一个toast,这样就验证了广播的优先级

既然已经得到了广播的优先级,那么我们可以选择是否广播继续传递,修改代码

public class AnotherBroadcaseReceiver extends BroadcastReceiver {

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

调用abortBroadcast方法,就表示广播被截端,后边无法继续收到广播,测试结果和预期一样,美滋滋

4.使用本地广播
前面我们发送和接收的广播全部属于全局广播,发出的广播可以被其他应用所截获,为了解决广播的安全性,andorid引入了,本地广播机制,使用这个机制发出的广播只能在本app之中传奇,并且广播接收器也只能接收到来自本应用的广播
本地广播的用法并不复杂,主要就是使用一个localBroadcastManager,来对广播进行管理,并提供了发送广播和注册广播接收器的方法,下面我们来试下

public class SanActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_san);
        localBroadcastManager=LocalBroadcastManager.getInstance(this);
        Button button=(Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent("fxr2");
                localBroadcastManager.sendBroadcast(intent);

            }
        });
        intentFilter=new IntentFilter();
        intentFilter.addAction("fxr2");
        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,"receiver local broadcast",Toast.LENGTH_SHORT).show();
        }
    }
}

通过localBroadcastManager的getInstance()方法得到实例,然后注册广播的时候调用LocalBroadcastManager的registerReceiver()方法,
点击按钮
这里写图片描述

可以看到,我们成功的接收到了本地广播,
另外还有一点需要说明,本地广播是无法进行静态注册的方式来接收的,

最后我们来盘点下使用本地广播的几点优势吧
1.快,是真的快,比全局的广播要快很多
2.可以明确的知道正在发送的广播不会离开我们的程序,因此不必担心机密数据泄漏。
3.真的是比全局广播要快,谁用谁知道


写不动了要睡觉了,明天再补充一个demo,然后找下网上有木有比较好用的广播技巧


附件
一.系统广播定义的一些action值展示:

1.Intent.ACTION_AIRPLANE_M; 
       关闭或打开飞行模式时的广播 
2.Intent.ACTION_BATTERY_CH; 1)充电状态,或者电池的电量发生变化; 2)电池的充电状态、电荷级别改变,不能通过组建声; 
3.Intent.ACTION_AIRPLANE_MODE_CHANGED; 
        关闭或打开飞行模式时的广播 
4.Intent.ACTION_BATTERY_CHANGED; 1)充电状态,或者电池的电量发生变化 
       (2)电池的充电状态、电荷级别改变,不能通过组建声明 接收这个广播,只有通过registerReceiver()注册 
5.Intent.ACTION_BATTERY_LOW; 
       表示电池电量低 
6 .Intent.ACTION_BATTERY_OKAY; 
       表示电池电量充足,即从电池电量低变化到饱满时会发出广播 
7.Intent.ACTION_BOOT_COMPLETED; 
       在系统启动完成后的广播,这个动作被广播一次(只有一次)。 
8.Intent.ACTION_CAMERA_BUTTON; 
       按下照相时的拍照按键(硬件按键)时发出的广播 
9.Intent.ACTION_CLOSE_SYSTEM_DIALOGS; 
       当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息 
10.Intent.ACTION_CONFIGURATION_CHANGED; 
       设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java) 
11.Intent.ACTION_DATE_CHANGED; 
       设备日期发生改变时会发出此广播 
12.Intent.ACTION_DEVICE_STORAGE_LOW; 
       设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用 
13.Intent.ACTION_DEVICE_STORAGE_OK; 
       设备内存从不足到充足时发出的广播,此广播       只能由系统使用,其它APP不可用 
14.Intent.ACTION_DOCK_EVENT; 
       发出此广播的地方 
frameworks\base\services\java\com\android\server\DockObserver.java 
15.Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE; 
       移动APP完成之后,发出的广播(移动是指:APP2SD) 
16.Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; 
       正在移动APP时,发出的广播(移动是指:APP2SD) 17. 
17.Intent.ACTION_GTALK_SERVICE_CONNECTED; 
       Gtalk已建立连接时发出的广播 
18.Intent.ACTION_GTALK_SERVICE_DISCONNECTED; 
       Gtalk已断开连接时发出的广播 
19.Intent.ACTION_HEADSET_PLUG; 
       在耳机口上插入耳机时发出的广播 
20.Intent.ACTION_INPUT_METHOD_CHANGED; 
       改变输入法时发出的广播 
21.Intent.ACTION_LOCALE_CHANGED; 
       设备当前区域设置已更改时发出的广播 
22.Intent.ACTION_MANAGE_PACKAGE_STORAGE; 
       表示用户和包管理所承认的低内存状态通知应该开始。 
23. Intent.ACTION_MEDIA_BAD_REMOVAL; 
       未正确移除SD卡(正确移除SD卡的方法:设置–SD卡和设备内存–卸载SD卡),但已把SD卡取出来时发出的广播 ,扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mountpoint) 还没解除 (unmount) 
24.Intent.ACTION_MEDIA_BUTTON; 
       按下”Media Button” 按键时发出的广播,假如有”Media Button” 按键的话(硬件按键) 
25. Intent.ACTION_MEDIA_CHECKING; 
       插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播。 
26.Intent.ACTION_MEDIA_EJECT; 
       已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播, 用户想要移除扩展介质(拔掉扩展卡)。 
27.Intent.ACTION_MEDIA_MOUNTED; 
       插入SD卡并且已正确安装(识别)时发出的广播, 扩展介质被插入,而且已经被挂载。 
28.Intent.ACTION_MEDIA_NOFS; 
       拓展介质存在,但使用不兼容FS(或为空)的路径安装点检查介质包含在Intent.mData领域。 
29. Intent.ACTION_MEDIA_REMOVED; 
       外部储存设备已被移除,不管有没正确卸载,都会发出此广播, 扩展介质被移除。 
30.Intent.ACTION_MEDIA_SCANNER_FINISHED; 
       广播:已经扫描完介质的一个目录 
31.Intent.ACTION_MEDIA_SCANNER_SCAN_FILE; 
       请求媒体扫描仪扫描文件并将其添加到媒体数据库。 
32.Intent.ACTION_MEDIA_SCANNER_STARTED; 
       广播:开始扫描介质的一个目录 
33. Intent.ACTION_MEDIA_SHARED; 
       广播:扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享。 
34.Intent.ACTION_MEDIA_UNMOUNTABLE; 
35.Intent.ACTION_MEDIA_UNMOUNTED 
       广播:扩展介质存在,但是还没有被挂载 (mount) 
36.Intent.ACTION_NEW_OUTGOING_CALL; 
37. Intent.ACTION_PACKAGE_ADDED; 1)成功的安装APK之后 
       (2)广播:设备上新安装了一个应用程序包。 
       (3)一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播) 
38.Intent.ACTION_PACKAGE_CHANGED; 
       一个已存在的应用程序包已经改变,包括包名 
39.Intent.ACTION_PACKAGE_DATA_CLEARED; 1)清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?) 
       (2)用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播) 
40.Intent.ACTION_PACKAGE_INSTALL; 
       触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用? 
41.Intent.ACTION_PACKAGE_REMOVED; 
       成功的删除某个APK之后发出的广播, 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播) 
42.Intent.ACTION_PACKAGE_REPLACED; 
       替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?) 
43.Intent.ACTION_PACKAGE_RESTARTED; 
       用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播) 
44.Intent.ACTION_POWER_CONNECTED; 
       插上外部电源时发出的广播 
45.Intent.ACTION_POWER_DISCONNECTED; 
       已断开外部电源连接时发出的广播 
46.Intent.ACTION_PROVIDER_CHANGED; 
47.Intent.ACTION_REBOOT; 
       重启设备时的广播 
48.Intent.ACTION_SCREEN_OFF; 
       屏幕被关闭之后的广播 
49. Intent.ACTION_SCREEN_ON; 
       屏幕被打开之后的广播 
50.Intent.ACTION_SHUTDOWN; 
       关闭系统时发出的广播 
51. Intent.ACTION_TIMEZONE_CHANGED; 
       时区发生改变时发出的广播 
52.Intent.ACTION_TIME_CHANGED; 
       时间被设置时发出的广播 
53.Intent.ACTION_TIME_TICK; 
       广播:当前时间已经变化(正常的时间流逝), 当前时间改变,每分钟都发送,不能通过组件声明来接收 ,只有通过Context.registerReceiver()方法来注册 
54. Intent.ACTION_UID_REMOVED; 
       一个用户ID已经从系统中移除发出的广播 
55. Intent.ACTION_UMS_CONNECTED; 
设备已进入USB大容量储存状态时发出的广播? 
56.Intent.ACTION_UMS_DISCONNECTED; 
       设备已从USB大容量储存状态转为正常状态时发出的广播? 
57.Intent.ACTION_USER_PRESENT; 
58.Intent.ACTION_WALLPAPER_CHANGED; 
       设备墙纸已改变时发出的广播
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值