首页 > 其他分享 >Android BroadcastReceiver

Android BroadcastReceiver

时间:2023-01-17 13:58:12浏览次数:34  
标签:Toast MyBroadcastReceiver 广播 intent 注册 Android BroadcastReceiver

Android 中的每个应用程序都可以对自己 感兴趣的广播进行注册,这样该程序就只会收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。Android 提供了一套完整的API,允许应用程序自由地发送和接收广播。

广播类型

Android 中的广播主要可以分为两种类型:标准广播和有序广播。

  • 标准广播(normal broadcasts)是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver 几乎会在同一时刻收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
  • 有序广播(ordered broadcasts)则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个BroadcastReceiver 能够收到这条广播消息,当这个BroadcastReceiver 中的逻辑执行完毕后,广播才会继续传递。所以此时的BroadcastReceiver 是有先后顺序的, 优先级高的BroadcastReceiver 就可以先收到广播消息,并且前面的BroadcastReceiver 还可以截断正在传递的广播,这样后面的BroadcastReceiver 就无法收到广播消息了。

接收系统广播

注册BroadcastReceiver 的方式一般有两种:在代码中注册和在AndroidManifest.xml 中注册。其中前者也被称为动态注册,后者也被称为静态注册。

动态注册

新建一个类,让它继承自 BroadcastReceiver ,并重写父类的onReceive()方法就行了。这样当有广播到来时, onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。

class MainActivity : AppCompatActivity() {

    lateinit var timeChangeReceiver: TimeChangeReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intentFilter = IntentFilter()
        // 当系统时间发生变化时,系统发出的正是一条值为android.intent.action.TIME_TICK的广播
        intentFilter.addAction("android.intent.action.TIME_TICK")
        timeChangeReceiver = TimeChangeReceiver()
        // 后调用registerReceiver()方法进行注册
        registerReceiver(timeChangeReceiver, intentFilter)
    }

    override fun onDestroy() {
        super.onDestroy()
        // 动态注册的BroadcastReceiver一定要取消注册才行
        unregisterReceiver(timeChangeReceiver)
    }

    // 定义了一个内部类TimeChangeReceiver,这个类是继承自BroadcastReceiver的,并重写了父类的onReceive()方法。
    inner class TimeChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()
            Log.i("MainActivity", "Time has changed" + Toast.LENGTH_SHORT.toString())
        }
    }
}

Android 系统还会在亮屏熄屏、电量变化、网络变化等场景下发出广播。如果你想查看完整的系统广播列表,可以到如下的路径中去查看: 

<Android SDK>/platforms/<任意android api版本>/data/broadcast_actions.txt 

 静态注册

其实从理论上来说,动态注册能监听到的系统广播,静态注册也应该能监听到,在过去的 Android 系统中确实是这样的。但是由于大量恶意的应用程序利用这个机制在程序未启动的情况 下监听系统广播,从而使任何应用都可以频繁地从后台被唤醒,严重影响了用户手机的电量和性能,因此Android 系统几乎每个版本都在削减静态注册BroadcastReceiver 的功能。

在Android 8.0 系统之后,所有隐式广播都不允许使用静态注册的方式来接收了。隐式广播指的 是那些没有具体指定发送给哪个应用程序的广播,大多数系统广播属于隐式广播,但是少数特 殊的系统广播目前仍然允许使用静态注册的方式来接收。这些特殊的系统广播列表详见 https://developer.android.google.cn/guide/components/broadcastexceptions.html 。

class BootCompleteReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show()
        Log.i("BootCompleteReceiver", "Boot Complete")
    }
}

AndroidManifest.xml 文件进行修改  

<receiver
    android:name=".BootCompleteReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

发送自定义广播

广播主要分为两种类型:标准广播和有序广播。

发送标准广播

在发送广播之前,我们还是需要先定义一个BroadcastR eceiver 来准备接收此广播

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show()
        Log.i("MyBroadcastReceiver", "received in MyBroadcastReceiver")
    }
}

然后在AndroidManifest.xml 中对这个BroadcastReceiver 进行修改:

<receiver
    android:name=".MyBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    </intent-filter>
</receiver>

接下来修改activity_main.xml 中的代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Broadcast" />
</LinearLayout>

然后修改MainActivity 中的代码

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.i("MainActivity", "onCreate")
        button.setOnClickListener {
            val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }
    }
}

发送有序广播

和标准广播不同,有序广播是一种同步执行的广播,并且是可以被截断的。

新建AnotherBroadcastReceiver

class AnotherBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show()
        Log.i("AnotherBroadcastReceive", "received in AnotherBroadcastReceiver")
    }
}

然后在AndroidManifest.xml 中对这个BroadcastReceiver 的配置进行修改

<receiver
    android:name=".AnotherBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    </intent-filter>
</receiver>

发送有序广播只需要改动一行代码,即将sendBroadcast()方法改成 sendOrderedBroadcast()方法。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.i("MainActivity", "onCreate")
        button.setOnClickListener {
            val intent = Intent("com.example.broadcasttest.MY_BROADCAST")
            intent.setPackage(packageName)
            sendOrderedBroadcast(intent, null)
        }
    }
}

可以看到,AnotherBroadcastReceiver 同样接收的是 com.example.broadcasttest.MY_BROADCAST这条广播。现在重新运行程序,并点击“Send Broadcast” 按钮,就会分别弹出两次提示信息

android:priority优先级

如何设定BroadcastReceiver的先后顺序呢?当然是在注册的时候进行设定了,修改 AndroidManifest.xml 中的代码,如下所示:

<receiver
    android:name=".MyBroadcastReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="100">
        <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    </intent-filter>
</receiver>

通过android:priority属性给BroadcastReceiver 设置了优先级,优先级比较高的BroadcastReceiver 就可以先收到广播。这里将MyBroadcastReceiver 的优先级设成了100 ,以保证它一定会在AnotherBroadcastReceiver 之前收到广播。

abortBroadcast()广播截断

既然已经获得了接收广播的优先权,那么MyBroadcastReceiver 就可以选择是否允许广播继续传递了。修改MyBroadcastReceiver 中的代码,如下所示:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show()
        Log.i("MyBroadcastReceiver", "received in MyBroadcastReceiver")
        abortBroadcast()
    }
}

如果在onReceive()方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面 的BroadcastReceiver 将无法再接收到这条广播。

 

标签:Toast,MyBroadcastReceiver,广播,intent,注册,Android,BroadcastReceiver
From: https://www.cnblogs.com/ooo0/p/17057623.html

相关文章

  • Android开发 ViewPropertyAnimator动画属性
    前言ViewPropertyAnimator是基于ValueAnimator实现的,这点在ViewPropertyAnimator的源码中的 privatevoidstartAnimation()方法里可以看到。Android的动画实现方式......
  • Android Fragment
    Fragment是什么Fragment是一种可以嵌入在Activity当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛。Fragment的状态得每个Activ......
  • Android 相关
    Android-Project模式的项目结构AndroidActivityAndroidFragment......
  • Android之简单控件
    1.1文本显示本小节讲述如何设置文本的大小,内容,颜色,背景对于文本控件来说,用text属性给文本赋值,设置文本的内容,当然最好用String.xml来表示设置文本的大小用textSize表示,......
  • 直播平台搭建,Android手机拍照和手机相册选取图片的工具
    直播平台搭建,Android手机拍照和手机相册选取图片的工具packagecom.shentaiwang.jsz.savepatient.util; importandroid.app.Activity;importandroid.content.ContentVa......
  • android studio 报错com.android.build.api.transform.TransformException: java.lang
    报错com.android.build.api.transform.TransformException:java.lang.RuntimeException或者其他一些出现gradle报错字样,这是因为部分第三方库需要较高gradle版本才能跑起......
  • 交叉编译 linux x86_64 aarch64 Android8
    https://github.com/TanNang/tls-proxy#uthashcd/tmpgitclonehttps://github.com/troydhanson/uthash#base64cd/tmpgitclonehttps://github.com/aklomp/bas......
  • android开发day4
    Activity组件屏幕组件启停活动页面启动结束生命周期启动模式在活动之间传递信息显示隐式Intent显示跳转隐式跳转发送数据返回数据补充附加信息......
  • Android开发学习之路--Camera之初体验
      顾名思义Camera就是拍照和录像的功能,像微信里面,我们想拍照传一下照片,就可以通过camera来拍照,然后存储照片,发送给好友。那么微信的app里面是不会直接通过cameraapi来......
  • Android开发学习之路--数据持久化之初体验
      上班第一天,虽然工作上处于酱油模式,但是学习上依旧不能拉下,接着学习android开发吧,这里学习数据持久化的知识。  其实数据持久化就是数据可以保存起来,一般我们保存......