Android四大组件之Broadcast

来源:互联网 发布:java图形小程序代码 编辑:程序博客网 时间:2024/06/05 16:52

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

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;        设备墙纸已改变时发出的广播