Android BroadCast 各种注册和发送方式的特点整理以及7.0以上版本的使用变化

写在最前面!
为什么一定要整理博客或者技术笔记,个人的一些感想!

写在前面:
本篇文章的内容都是作者通过阅读BroadCast的官方文档并结合自己的开发经验整理而成的。
英文好的同学请移步,看官方文档之前,我还是建议大家看一下这篇文章,因为这篇的整体的结构和每个知识的说明我都整理了一番。可以方便大家快速的理解!https://developer.android.com/guide/components/broadcasts.html#restricting_broadcasts_with_permissions

1.什么是广播?

  说起广播我们都很熟悉,Android系统中我们可以在应用内部发送和接收广播,也可以是发送和接收广播到别的应用或者系统。只需要我们能够按照特定的格式进行广播的注册配置,我们就可以接收和发送指定的广播。类似于观察者模式。 比如系统启动的时候,系统会发送启动的这个动作的广播给所有注册接收这个动作的应用。 再比如:我们应用完成了一个下载数据的操作,可以发送一个广播通过其他组件进行接收。

2.广播的注册和发送广播都有哪些方式,都有什么区别?

   广播的注册方式有两种,广播的发送方式目前有四种。我们应该在分析清楚每种方式的不同点和注意事项,以便在实际的开发过程中能够正确的使用它 。

首先来看广播的注册方式的区别(ps:注册步骤太简单了。看官方文档吧,这里只说明两种注册方式的区别):

1.在清单文件中注册广播
特点:

  • 1.系统的包管理器会在应用安装的时候注册这些广播。如果你注册了一个这种广播,当这个广播发送的时候,如果你的应用没有启动。系统会启动你的应用。
  • 2.系统会新创建一个BroadcastReceiver对象来处理广播,这个对象的生命周期取决于onReceive()方法的执行时间。如果onReceive方法return了, 那系统就认为这组件不再存活了。

    这种广播的注册和接收有很大的问题,所以在高版本的api(android8.0)上不再支持这种方式注册广播。这些问题我们在之后会讲到!

2.调用context的registered注册广播
特点:

  • 1.这种方式注册的广播能够接收广播的有效时间取决于注册使用的context的存活时间。如果context使用的是Activity,那么在Activity没有onDestroy()之前他都是可以接收到广播的。如果使用的是ApplicationContext那么在整个应用运行期间他都是可以接收到广播的。
  • 2.要注意在哪里注册了就应该在对应的位置取消注册,避免广播出现问题。比如你在Activity的onCreate()方法中注册了广播,就应该在onDestory()方法取消注册,避免广播出现内存泄漏。如果是在onResume()方法中注册了广播就应该在onPause()中取消注册。避免出现重复注册的情况!

接下来我们看看4种不同的广播发送的方式(ps:这里还是只整理区别,具体的调用方式还是请查看相关文档!):

第1种广播发送的方式:使用sendBroadcast(Intent)发送广播,这种广播一般也叫普通广播。
特点:
这种方式发送的广播可以一次分发给所有的注册接收这个广播的接收者。而且分发没有先后顺序。但是这种方式的广播接收者之间不能进行数据的传递,接收者也不能打断广播的传递。

第2种广播发送的方式: 2.使用 sendOrderedBroadcast()方法发送广播。这种广播也叫有序广播。
特点:

  • 使用这种方式发送的广播一次只能发送给一个接收者,每个接收者之间可以进行数据依次传递,每个接收者也可以打断广播的传递。 接收者的优先级顺序通过 android:priority 属性进行标识,同优先级的广播接收者的接收顺序随机!

第3种广播发送的方式:使用LocalBroadcastManager.sendBroadcast()发送广播
特点:

  • 通常我们使用sendBroadcast和sendOrderedBroadcast发送的广播都是有数据安全问题的,因为我们发送的广播其他应用也是接收到这些广播的。 所以Android系统在api22的时候提供了LocalBroadcastManager.sendBroadcast()这个方式发送广播,这种方式发送的广播只允许和发送者在同一个应用中的广播接收者可以接收广播。 这样就避免了数据安全问题。
    ps:
    1.当然在api22以下的时候我们也可以通过intent.setPackage(String)来限定可以接收广播的应用。
    2.如果要接收这种方式发送的广播,注册的时候需要通过LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter)注册。

第4种广播发送的方式:发送和接收广播的时候添加权限限制。
特点:

  • 这种方式其实不能算是一种发送广播的方式,所有我们之前的注册广播和发送广播的方式都可以添加这个限制,如果广播添加了权限限制,那么发送和接收广播的时候必须要匹配对应的权限才能发送和接收。

代码示例:

发送广播的时候添加权限限制:

  sendBroadcast(new Intent("com.example.NOTIFY"),Manifest.permission.SEND_SMS);

接收权限限制发送的广播的注册方式:
1.清单文件中注册并添加权限限制

<receiver android:name=".MyBroadcastReceiver"
          android:permission="android.permission.SEND_SMS">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

2.调用context的registered注册广播并添加权限限制

 IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
 registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );

3.Android7.0之后广播的发送和接收都有什么改变?

Android7.0开始对广播的行为方式有了一些调整,了解清楚这些知识点是我们做好高版本系统中广播的使用兼容的基础!

变更1:Android7.0或者更高的版本不会再发送以下两个广播了,这些会影响所有应用不仅仅是哪些target是Android7.0的应用

  • ACTION_NEW_PICTURE
  • ACTION_NEW_VIDEO

变更2:Android7.0或者更高的版本不能在清单文件中注册下面这个广播了,只能使用动态注册的方式

  • CONNECTIVITY_ACTION

变更3:从Android8.0(Api lenovo)开始, 系统限制了在清单文件中注册可以接收的广播。只有一些广播例外.https://developer.android.com/guide/components/broadcast-exceptions.html

那么为什么7.0以后的版本要限制广播呢?
因为通过清单文件注册的广播,会被一些系统的事件触发。而每次发送广播时,应用的接收器都会消耗资源。 如果多个应用注册为接收基于系统事件的广播,这会引发问题;触发广播的系统事件会导致所有应用快速地连续消耗资源,从而降低用户体验。

4.广播对于进程优先级的影响?

  我们知道Android系统有进程优先级的概念,而运行的广播是可以影响所在进程的优先级的,如果有广播执行了onReceiver方法那么当前进程的优先级就会提高到前台进程的级别。就种情况下的进程只有极少数的情况才会被杀死,所以能够保证广播的正常执行。但是如果onReceiver中执行了return方法的话那么进程的优先级就会降到当前进程所有的其他组件的保持的状态。 这种情况下如果进程的优先级不高的话。是有很大几率被杀死的。 所以为了保证广播代码能够正常执行完成,我们需要有两种方法保证在广播中的代码执行期间, 进程不会回收!
goAsync()和JobScheduler这里示例第一种,示例代码如下(第二种请参考链接):

public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";

    @Override
    public void onReceive(final Context context, final Intent intent) {
        final PendingResult pendingResult = goAsync();
        AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
            @Override
            protected String doInBackground(String... params) {
                StringBuilder sb = new StringBuilder();
                sb.append("Action: " + intent.getAction() + "\n");
                sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
                Log.d(TAG, log);
                // Must call finish() so the BroadcastReceiver can be recycled.
                pendingResult.finish();
                return data;
            }
        };
        asyncTask.execute();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值