浅谈广播

浅谈广播

广播属于Android四大组件之一,它的主要用于APP内部组件间的通讯,负责监听、接收、分发App内部的广播消息并做响应。我还理解的比较浅显,此篇文章也是借鉴了很多文章后的产物,有错误望指出。

原理分析

在这里插入图片描述

实现步骤(以广播网络状态为例)
  • 定义广播接受器BroadcastReceiver
  • 注册广播接收器
  • 发布广播

1. 定义广播接受器BroadcastReceiver
继承BroadcastReceivre类,重写onReceive()方法

//网络广播接受器
public class NetBroadcastReceiver extends BroadcastReceiver {
	private NetEvent netEvent;
	@Override
	public void onReceive(Context context, Intent intent) {
		//在这里写上相关的处理代码,一般来说,不要此添加过多的逻辑或者是进行任何的耗时操作
        //因为广播接收器运行在UI线程,不允许开启多线程的,过久的操作就会出现报错
        //因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如创建一条状态栏通知,或者启动某个服务
		if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
			int netWrokState = NetUtil.getNetWorkState(context);
			if (netEvent != null)
				netEvent.onNetChange(netWrokState);
		}
	}
}

2. 注册广播接收器
注册有两种方式:静态/动态注册

静态注册
注册方式:在AndroidManifest.xml中通过<receive>标签声明。

<!-- APP首次启动时,系统自动实例化 NetBroadcastReceiver 类,并将其注册到系统中 -->
<receiver 
    //广播接收者器的名字
    android:name=".NetBroadcastReceiver " >
    //用于接收网络状态改变时发出的广播
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

动态注册
注册方式:在activity中的onResume()方法中注册,在onPause()方法中销毁

/*
*选择Activity生命周期方法中的onResume()和onPause()是由于
*当系统内存不足(优先级更高的应用需要内存)要回收Activity占用的资源时,
*Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()不会执行
*所以没有使用【onStart() , onStop()】或者【onCreate() ,onDestory()】
*/
@Override
  protected void onResume(){
      super.onResume();

    // 1. 实例化BroadcastReceiver子类 &  IntentFilter
     NetBroadcastReceiver netBroadcastReceiver = new NetBroadcastReceiver ();
     IntentFilter intentFilter = new IntentFilter();
     
    // 2. 设置接收广播的类型
    intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

    // 3. 动态注册:调用Context的registerReceiver()方法
     registerReceiver(netBroadcastReceiver , intentFilter);
 }

// 当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
// 当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
 @Override
 protected void onPause() {
     super.onPause();
      //销毁在onResume()方法中的广播
     unregisterReceiver(netBroadcastReceiver );
     }
}

静态|动态注册的区别
在这里插入图片描述
3. 发送广播

发送广播 = 广播发送者 将此广播的“意图(Intent)”通过sendBroadcast()方法发送出去。

广播的5种类型:

  • 普通广播(Normal Broadcast
  • 系统(全局)广播(System Broadcast
  • 有序广播(Ordered Broadcast
  • 粘性广播(Sticky BroadcastAndroid5.0 & API 21之后已经失效
  • 本地(局部)广播(Local Broadcast

3.1 普通广播
开发者自身定义 intent的广播(最常用)。发送广播使用如下:

Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//发送广播
sendBroadcast(intent);

3.2 系统广播

Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播。
使用系统广播时不需要发送广播,只要定义和注册接收器即可。

每个Android系统广播都有特定的action:
在这里插入图片描述
3.3 有序广播
有序广播是针对广播接收者说的。

特点
有序广播的接收者们将按照事先生命的优先级依次接收,数越大优先级越高(取值范围:-1000~10000),优先级可以声明在<intent-filter android:priority=“n”…/>,也可以调用IntentFilter对象的setPriority设置。并且接收者可以终止传播(调用abortBroadcast()方法终止传播),一旦终止后面接收者就无法接受广播。另外,接受者可以将处理结果存入数据(可通过setResultExtras(Bundle)方法将数据存入Broadcast),当做Broadcast再传递给下一级接收者(可通过代码Bundle bundle = getResultExtras(true)获取上一级传递过来的数据)。

短信拦截原理:系统收到短信,发出的Broadcast属于有序广播,程序就可以通过设定优先级先接收到通知,然后终止传递。
  有序广播的案例:
1.首先创建两个BroadcastReceiver。让第一个receive接收到广播后中断。

public class HighReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("HighReceiver接受到消息");
        abortBroadcast(); //中断广播,比它优先级低得广播不会再传播下去
    }
}
public class LowReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("LowReceiver接受到消息");
    }
}

2.然后将两个receiveractionAndroidManifest.xml文件中配置成一样的,并且设置成不同的优先级。

<receiver android:name=".HighReceiver ">
            <!-- priority优先级:数字越高优先级越高 -->
            <intent-filter android:priority="5" >
                <action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
            </intent-filter>
        </receiver>
        <receiver android:name=".LowReceiver ">
            <intent-filter android:priority="4">
                <action android:name="com.codingblock.myreceiver.intent.action.MyReceiver"/>
            </intent-filter>
        </receiver> 

3.最后在MainActivity中发送广播。

public class MainActivity extends Activity {

   Button btn_send_receiver;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       btn_send_receiver = (Button)findViewById(R.id.btn_send_receiver);
       btn_send_receiver.setOnClickListener(new OnClickListener() {
           
           @Override
           public void onClick(View v) {
               Intent intent = new Intent();
               intent.setAction("com.codingblock.myreceiver.intent.action.MyReceiver");
               sendOrderedBroadcast(intent, null);//有序广播用sendOrderedBroadcast()方法发送广播
           }
       });
   }
}

点击按钮后只有HighReceiver接收到了消息,广播就被中断了,LowReceiver不会接收到广播。
3.4 本地广播

特点
本地广播只能用于应用内通信,本地广播携带的信息不会暴露给其他App,其他App也无法伪造广播来起欺骗你的receiver,安全性很好,同时拥有更高的运行效率。也是需要发送应用内广播时的官方推荐。

1.可将全局广播设置成局部广播

  • 全局广播可以在注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收。
  • 在广播发送和接收时,增设相应权限permission,用于权限验证。
  • 发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中,eg:intent.setPackage(packageName)指定包名。

2.用局部广播LocalBroadcastReceiver

LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。
在发送和注册的时候采用,LocalBroadcastManagersendBroadcast方法和registerReceiver方法

//步骤1:实例化自定义的NetBroadcastReceiver和IntentFilter
NetBroadcastReceiver netBroadcastReceiver = new NetBroadcastReceiver (); 
IntentFilter intentFilter = new IntentFilter(); 

//步骤2:实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);

//步骤3:设置接收广播的类型 
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);

//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册 
localBroadcastManager.registerReceiver(netBroadcastReceiver, intentFilter);

//取消注册本地广播接收器
localBroadcastManager.unregisterReceiver(netBroadcastReceiver);

//发送本地广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);

猜你喜欢

转载自blog.csdn.net/weixin_42824294/article/details/87929751