三、基本组件(三)深入理解BroadcastReceiver

1. 广播简介

       BroadcastReceiver也就是“广播接收者”的意思,顾名思义,就是用来接收来自系统和应用中的广播,是一种广泛运用在应用程序之间传输信息的机制。在 Android 里面有各种各样的广播,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能,当网络状态改变时,系统会产生一条广播,接收到这条广播,就能及时的做出提示和保存数据等操作,当电池的电量改变的时候,系统会产生一条广播,接收到这条广播就能在电量低的时候告知用户,及时保存进度。

2.广播接收器的类型

2.1 普通广播(Normal Broadcast)

       普通广播是开发者自身定义intent的广播(最常用)。发送一条默认的广播使用Context.sendBroadcast()方法,普通广播对于多个接受者来说是异步的,通常每个接受者都无需等待即可以接收到广播,接受者之间互相不会有影响,对于这种广播,接受者无法终止广播,即无法阻止其他接受者的接收动作。

使用步骤1:创建Receiver

public class MyReceiver extends BroadcastReceiver {
        public MyReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            String info = intent.getStringExtra("info");
            Toast.makeText(context, info, Toast.LENGTH_LONG).show();
        }
}

使用步骤2:在Manifest文件中注册

    <receiver android:name=".MyReceiver"
              android:enabled="true"
              android:exported="true">
        <intent-filter>
            <action android:name="com.wxt.action.BROADCAST"></action>
        </intent-filter>
    </receiver>

使用步骤3:调用广播

    public class MainActivity extends AppCompatActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.wxt.action.BROADCAST");
                    intent.putExtra("info","广播广播啦啊");
                    MainActivity.this.sendBroadcast(intent);
                }
            });
        }
    }

2.2 有序广播

       有序广播是指发送出去的广播被广播接收者按照先后顺序接收,有序是针对广播接收者而言的。发送一个有序广播使用Context.sendOrderedBroadcast( )方法,有序广播比较特殊,它每次只发1个到优先级较高的接受者那里,然后由优先级较高的接受者再传播到优先级别低的接受者那里,优先级高的接受者有能力终止这个广播。
       广播接受者接受广播的优先级顺序是按照Priority属性值从大到小排序,数越大优先级越高(取值范围:-1000~10000),如果Priority属性相同则动态注册的广播优先。
       先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播。
       使用sendOrderedBroadcast方法有序广播的时候,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者要接收此广播,需声明指定权限,这样做是从安全角度考虑的,例如系统的短信就是有序的广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来的时候它可以先接收到短信,必要时候终止广播的传递,这样的软件就必须声明接收短信的权限。

使用步骤1:创建第一个OrderReceiver

public class OrderReceiver extends BroadcastReceiver {
    public OrderReceiver() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String info = intent.getStringExtra("info")+" receiver 01";
        Toast.makeText(context,info,Toast.LENGTH_LONG).show();
    }
}

使用步骤2:创建第二个OrderReceiver

public class OrderReceiver2 extends BroadcastReceiver {
    public OrderReceiver2() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String info = intent.getStringExtra("info")+" receiver 02";
        Toast.makeText(context,info,Toast.LENGTH_LONG).show();
    }
}

使用步骤3:在manifest文件中注册

    <receiver android:name=".OrderReceiver"
              android:enabled="true"
              android:exported="true">
        <intent-filter android:priority="100">
            <action android:name="com.wxt.action.ORDER_BROADCAST"></action>
        </intent-filter>
    </receiver>

    <receiver android:name=".OrderReceiver2"
              android:enabled="true"
              android:exported="true">
        <intent-filter android:priority="200">
            <action android:name="com.wxt.action.ORDER_BROADCAST"></action>
        </intent-filter>
    </receiver>

使用步骤4:调用广播

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.wxt.action.ORDER_BROADCAST");
                intent.putExtra("info","我是有序广播");
                MainActivity.this.sendOrderedBroadcast(intent,null);
            }
        });
    }
}

2.3 粘性广播

       当处理完之后的intent,依然存在,直到将它去掉。发送粘性广播使用:sendStickBroadcast(intent)。由于在Android5.0 & API 21中已经失效,所以不建议使用,在这里也不作过多的总结。

2.4 系统广播

       Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播。
       每个广播都有特定的Intent - Filter(包括具体的action),Android系统广播action如下:
这里写图片描述
注意:当使用系统广播的时候,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作的时候会自动进行系统广播。

2.5 应用内广播

       Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true),可能会出现其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理,也有可能出现其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息,即会出现安全性和效率性的问题。针对此问题,可以使用应用内广播。App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App,相比于全局广播(普通广播),App应用内广播优势体现在:安全性高和效率高。

2.5.1 使用方法1:将全局广播设置为局部广播

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

2.5.2 使用方法2:使用封装好的LocalBroadcastManager类

       使用方式上与全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例。对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。

//注册应用内广播接收器
//步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver
mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();

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

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

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

//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

//发送应用内广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);

3.注册广播的两种方式(静态注册和动态注册)

3.1 静态注册

       静态注册是指是指在AndroidManifest.xml文件中配置,当此App首次启动时,系统会自动实例化mBroadcastReceiver类,并注册到系统中。

<receiver
    android:enabled=["true" | "false"]
    //此broadcastReceiver能否接收其他App的发出的广播
    //默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    //继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
    //具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
    //BroadcastReceiver运行所处的进程
    //默认为app的进程,可以指定独立的进程
    //注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

    //用于指定此广播接收器将接收的广播类型
    //本示例中给出的是用于接收网络状态改变时发出的广播
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>




    注册示例:
<receiver android:name=".MyReceiver"
          android:enabled="true"
          android:exported="true">
<intent-filter>
    <action android:name="com.wxt.action.BROADCAST"></action>
</intent-filter>
</receiver>

3.2 动态注册

       动态注册是指在代码中通过调用Context的registerReceiver()方法进行动态注册BroadcastReceiver

   @Override
    protected void onResume() {
        super.onResume();

        //实例化BroadcastReceiver子类 & IntentFilter
        mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();

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

        //调用Context的registerReceiver()方法进行动态注册
        registerReceiver(mBroadcastReceiver, intentFilter);
    }


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

特别注意:
动态广播最好在Activity的onResume( )中注册,onPause( )中注销;原因是动态广播有注册就需要有注销,否则会导致内存泄漏,在onResume()注册、onPause()注销是因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。

3.3 两种注册方式对比

这里写图片描述

4.实现原理

Android中的广播使用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。广播的原理示意图如下
这里写图片描述

原理描述:
(1)广播接受者通过Binder机制在AMS注册
(2)广播发送者通过Binder机制想AMS发送广播
(3)AMS根据广播发送者的要求,在已注册列表中,寻找合适的广播接受者,寻找依据时IntentFilter/Permission
(4)AMS将广播发送到合适的广播接受者相应的消息循环队列中
(5)广播接受者通过消息循环拿到此广播,并回调onReceive( )
注意:广播发送者和广播接受者的执行时异步的,发出去的广播不会关心有无接受者接收,也不确定接受者到底合适才能接收到

5.注意事项

对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的:
(1)对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
(2)对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
(3)对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
(4)对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值