欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android四大组件之Broadcast

程序员文章站 2022-04-11 22:05:09
Android四大组件之Broadcast。 Broadcast虽然是四大组件,但是感觉用到的挺少的,感觉项目中我只用到了判断网络状态和判断电量 下面整理资料,主要来源于郭霖的...

Android四大组件之Broadcast。

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

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

了解了广播的基本分类,有序广播,无序广播之后,我们来进行一些简单的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();
        }
    }


}

效果图
Android四大组件之Broadcast
动态注册的关闭,需要取消注册,这里,我们实在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();
    }
}

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

   
        

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

  
            
                
            
        

当然需要添加权限

   

Android四大组件之Broadcast

到目前为止,我们在广播接收器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();
    }
}

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


            
                
            
        

可以看到让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);
            }
        });

    }
}

Android四大组件之Broadcast

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”

 
            
                
            
        

这时候我们运行下这个demo2,然后运行下demo1,此时保证demo2在后台存在
我们点击demo的按钮,就会弹出来2个toast
Android四大组件之Broadcast
这就证明,我们程序发出来的广播,别的程序也能接收到,
不过,目前为止,我们都是发送的标准广播,我们尝试下发送有序广播,修改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 的配置文件中进行修改


            
                
            
        

可以看到,我们通过android:priority属性给广播设置了优先级,优先级比较高的可以先接收到关闭,我们吧demo2设置为100,我们在运行测试下
Android四大组件之Broadcast
可以先看到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()方法,
点击按钮
Android四大组件之Broadcast

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

最后我们来盘点下使用本地广播的几点优势吧
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; 
       设备墙纸已改变时发出的广播