Android广播机制详细介绍(广播分类、注册方式)


Android广播机制详细介绍(广播分类、注册方式)。


(一). 安卓广播的分类

a.标准广播

?
1
2
3
4
5
标准广播发出以后,所有的广播接收器,可以几乎在同一时刻同时接受到这条广播。
 
优点:效率高
 
缺点:不能被截断。

b.有序广播

?
1
2
3
4
5
6
7
     有序广播发出以后,同一时刻只能有一个广播接收器收到这条广播。优先级高的广播先接受到这条
 
广播。在当前广播接收器处理完自己的逻辑以后,可以执行两种动作:
 
     1 .继续传递广播
 
     2 .将广播截断

(二). 注册广播的方式

a. 动态注册

?
1
2
3
在代码中注册的广播,被称为动态注册。动态注册的广播,最后必须取消注册。这类广播,只有应用启
 
动了,才能接收到广播。

动态注册广播需要的东西

一个广播接收器类 —— 实质就是一个继承自BoradCastReceiver的类,只要继承这个类,就

具体接收广播的能力了,但是能接受什么广播由下面的第三条决定。

重写父类的onReceive()方法 —— 接收到广播的时候,就会回调这个方法。因此,广播接收

器的处理逻辑就写在这里

一个 IntentFilter 对象,广播接收器接收什么样的广播,由它的addAction()方法决定。

在代码中注册广播接收器,通过registerReceiver方法。方法接受两个参数,一个是广播接收

实例,一个是IntentFilter实例。

取消注册广播 ,通过unregisterReceiver() 方法—— 在哪里取消注册无所谓,只要保证取

消注册就OK

如果需要权限,则在AndroidManifest.xml文件申明权限


代码 :

布局代码:

?
1
2
3
4
5
6
7
<!--?xml version= "1.0" encoding= "utf-8" ?-->
<linearlayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:orientation= "vertical" xmlns:android= "https://schemas.android.com/apk/res/android" ><button android:id= "@+id/btn_isNetConnect" android:layout_gravity= "center" android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "检测网络" >
 
     <textview android:gravity= "center" android:id= "@+id/txt_show" android:layout_height= "80dp" android:layout_width= "match_parent" android:textsize= "30sp" >
 
 
</textview></button></linearlayout>

这里写图片描述

?
1
我们写一个简单的判断当前网络是否可用的广播。监听网络是一个敏感的动作,因此,需要在xml中申明权限。
?
1
<uses-permission android:name= "android.permission.ACCESS_NETWORK_STATE" ></uses-permission>

java 代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class MainActivity extends AppCompatActivity {
 
//     决定广播接收器接收什么广播
     private IntentFilter intentFilter ;
 
     private NetworkChangeReceiver networkChangeReceiver ;
     private TextView txt_show ;
     private Button btn_isNetConnect ;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
//        获取控件实例
         txt_show = (TextView) findViewById(R.id.txt_show);
         btn_isNetConnect = (Button) findViewById(R.id.btn_isNetConnect);
//        在按钮监听器中注册广播
         btn_isNetConnect.setOnClickListener( new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 intentFilter = new IntentFilter() ;
//       字符串 android.net.conn.CONNECTIVITY_CHANGE
//       表明广播接收器接收网络变化的广播
                 intentFilter.addAction( "android.net.conn.CONNECTIVITY_CHANGE" );
//        网络变化广播接收器实例
                 networkChangeReceiver = new NetworkChangeReceiver() ;
//        注册广播
//        别忘了,申明权限
                 registerReceiver(networkChangeReceiver,intentFilter) ;
             }
         });
     }
 
     /**
      * 动态注册的广播,必须在取消注册。
      * 我们在create(),方法创建的时候,注册了广播
      * 这里,我们在销毁活动中,取消注册,
      * 当然也可以在onPause()方法取消注册。
      */
     @Override
     protected void onDestroy() {
         super .onDestroy();
         unregisterReceiver(networkChangeReceiver);
     }
 
     /**
      * 用内部类实现一个网络变化广播接收器
      */
     class NetworkChangeReceiver extends BroadcastReceiver {
 
//        重写父类的onReceive()方法,接收到对应的广播的时候,就会回调这个方法
//        广播接收器的处理逻辑,就写此方法中
         @Override
         public void onReceive(Context context, Intent intent) {
//            获取网络管理服务类,就跟findViewById()方法一样
             ConnectivityManager connectivityManager =
                     (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
//            记住这样写。就好了。用到的时候,百度一下,边边角角,谁也记不清
             NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo() ;
//          判断网络状态
             if (networkInfo != null && networkInfo.isAvailable()){
                 txt_show.setText( "当前网络可用" );
             } else {
                 txt_show.setText( "当前网络不可用" );
             }
 
         }
     }
}

b.静态注册

?
1
2
3
在AndroidManifest.xml文件中注册的广播。这类广播,常驻广播,在应用未启动的时候,即可接收
 
到广播,处理相应的逻辑。

静态广播需要的东西

?
1
相比于动态注册的广播,静态广播需要的东西,就很少了。

依然需要一个广播接收器类

继续需要重写父类的onReceive()方法

在AndroidManifest.xml文件中注册广播

如果需要权限,则在AndroidManifest.xml文件申明权限


?
1
talk is cheap,show me code ! Or shut up

代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
  * 这里写将广播写为内部类
  * 目的;记住一个知识点:
  * 静态注册的广播,广播接收器为内部类的时候,必须是pubic static
 
  * 实现开机自启动
  * Created by MaiBenBen on 2017/10/16.
  */
public class Outter {
 
// 必须是public static
     public static class BootCompleteReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
//        调启主活动,来打开应用程序
//        context参数,就是此时的上下文
             Intent intent1 = new Intent(context,MainActivity. class );
             context.startActivity(intent1);
         }
     }
 
}

?
1
2
3
4
5
6
7
8
9
10
<!--
在AndroidManifest.xml文件中注册广播
内部类广播接收器的名字,写全了
-->
  <receiver android:enabled= "true" android:exported= "true" android:name= ".Outter$BootCompleteReceiver" >
             <intent-filter>
             <!--写明广播接收器接收的广播-->
                 </action>
             </intent-filter>
         </receiver>

?
1
2
监听开机广播 权限申明:
<uses-permission android:name= "android.permission.RECEIVE_BOOT_COMPLETED" ></uses-permission>

至此,已经成功完成了开机自启动。


(三). 发送广播

?
1
总是接受广播,也没劲。下面,我们自己来发送一些广播。发送的广播是自定义的。

a. 发送标准广播

?
1
2
3
4
5
广播是使用Intent,进行传递的。因此,我们可以在Intent中携带一些数据传递给广播接收器。
 
注意:这里只是在活动中发送广播,在服务或者广播中发送广播,代码有所不同:需要在intent中加上
 
标志。
?
1
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)。
?
1
2
3
该标志表明:首先寻找是否有与要启动的activity具有相同affinity的task。若没有,则生成一个新
 
的task,并将该activity放入其中;若有,则将该activity添加到该task的栈顶。
?
1
2
3
4
5
6
//        自定义广播内容
        String broadcast = "allbet.broad.cn.broadcasttest.MY_BROADCAST" ;
//        绑定到Intent中
        Intent intent = new Intent(broadcast) ;
//        发送广播,调用Context的sendBroadcast()方法
        sendBroadcast(intent);

b. 发送有序广播

?
1
有序广播与标准广播的发送方式,在代码中只有一句代码有差别,就是发送广播的方法不同。
?
1
2
3
4
5
6
7
8
//         自定义广播内容
       String broadcast = "allbet.broad.cn.broadcasttest.MY_BROADCAST" ;
//         绑定到Intent中
       Intent intent = new Intent(broadcast) ;
//         发送有序广播
//         第一个参数依然是Intent
//         第二个参数是代表权限的字符串,这里写null就好了
        sendOrderedBroadcast(intent, null );

有序广播发送完毕以后,优先级高的广播接收器会先收到

个广播。它们甚至可以将广播截,下面我们讲一下优先级的

问题


<☆> 广播接收器优先级

1.) 静态广播的优先级

跟目录的顺序有关,如下所示,目录越靠前,优先级越高,其中,第三方APP都在data/app

录下:

  system/framework
  
  system/app

  vendor/app

  data/app

  drm/app-private

当处于同一目录下时:按照file.list()的返回顺序。因为在data/app下的应用都是用户安装的,

并且都是以com.xxx.xxx-1.apk 的形式出现,它们的顺序,就是包名的顺序,因此,想要你的

应用的静态广播优先级高,就需要好好研究包名了,让你的应用包名靠前。但是这个顺序不是

绝对的,还依赖被扫描的先后顺序,先扫描的当然优先级高一点啦。即同一优先级的静态广播

接收器,先扫描的优先级高。一般都是包名排在前面的先被扫描。但是有人也说,是按照应用

安装的先后顺序。。。。有待考证

上面说的都是静态注册的时候,使用了相同优先级的情况。设置了优先级的,优先级越高,越

先接收到广播。


2.) 动态广播的优先级

一大影响因素,动态广播的注册时间。同一优先级的动态广播,先注册的优先级高。

动态注册的广播接收器的优先级永远高于静态注册的广播接收器。


综上所述,做个总结:

其实当接收广播的时候,广播接收器都会排队,无论是标准广播,还是有序广播,都是要排队

的,只不过,有序广播可能会被截断。

因此我们可以将,所有能接收该广播的广播接收器,理解为排队等着广播传递,排在前面的

人,当然就先接收到广播啦。那么谁排在前面呢?毫无疑问,一定是动态注册的广播,动态注

册的广播接收器们根据优先级排队,相同优先级的,就按照被扫描的先后顺序排队。排在队伍

后面的就只剩下静态注册的广播接收器了,也先根据优先级排序,相同优先级的,按照被扫描

的先后顺序排队。

上述的情况是,所有的广播接收器都不缺席的情况,但是总有广播接收器,由于种种原因(比

如,动态注册的广播,应用未启用)会缺席,缺席的话,那后面的广播接收器就自动补全空

位。


(四).为广播接收器设定优先级

a.为静态广播接收器设定优先级

?
1
在xml文件中设定
?
1
2
3
4
5
6
<receiver android:enabled= "true" android:exported= "true" android:name= ".Outter$BootCompleteReceiver" >
            <!--在这里添加属性-->
            <intent-filter android:priority= "100" >
                </action>
            </intent-filter>
        </receiver>

b.为动态广播设置优先级

?
1
在intentFilter对象上设置
?
1
2
3
4
5
6
7
8
9
10
11
         intentFilter = new IntentFilter() ;
//       字符串 android.net.conn.CONNECTIVITY_CHANGE
//       表明广播接收器接收网络变化的广播
                 intentFilter.addAction( "android.net.conn.CONNECTIVITY_CHANGE" );
//         设置优先级
                 intentFilter.setPriority( 1000 );
//        网络变化广播接收器实例
                 networkChangeReceiver = new NetworkChangeReceiver() ;
//        注册广播
//        别忘了,申明权限
                 registerReceiver(networkChangeReceiver,intentFilter) ;

(五).截断有序广播

?
1
2
3
有序广播在传送中,是可以被截断,甚至可以修改广播携带的数据。
 
截断广播,就是在广播接收器的onReceive()方法中调用abortBroadcast();
?
1
2
3
4
5
6
7
public void onReceive(Context context, Intent intent) {
/*
     处理逻辑
*/
//     逻辑处理结束,截断广播。
     abortBroadcast();
}

(六) 本地广播

?
1
2
3
之前我们发送的广播,都是系统全局广播,即我们发送的广播,能被系统的其他程序也接收到。这样是
 
很不安全的,因为,广播上说不定会携带着关键数据。或者,其他程序,不停的向我们发生垃圾广播。

本地广播,是无法再通过静态注册的广播接收器收到的。很好理解,静态注册,是为了程序未启动的

时候接收广播,而本地广播,程序已然启动可了。当然,也不能注册本地广播。

因此,我们需要本地广播,顾名思义,广播,只能在本程序中发送和接收。


a.本地广播需要的东西

对比全局广播,本地广播需要一个LocalBroadcastManger对象,来对广播进行管理。
?
1
2
3
4
5
6
//       获取本地广播管理 实例
         localBroadcastManager = LocalBroadcastManager.getInstance( this );
  intentFilter = new IntentFilter( "com.yaz.QQQ" ) ;
         myLocalBr  = new MyLocalBr() ;
         localBroadcastManager.registerReceiver(myLocalBr,intentFilter);
         break ;


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM