Kotlin开发第五天,广播BroadcastReceiver

完整代码Gitee地址:kotlin-demo: 15天Kotlin学习计划

第五天学习内容代码:Chapter5

目录

前言

定义

应用场景

知识点1:静态注册广播

知识点2:动态注册广播

知识点3:自定义全局广播


前言

  • BroadcastReceiver(广播接收器),属于 Android 四大组件之一
  • Android 开发中,BroadcastReceiver 的应用场景非常多
  • 今天,我将详细讲解关于BroadcastReceiver的一切相关知识

定义

即 广播,是一个全局的监听器,属于Android四大组件之一

Android 广播分为两个角色:广播发送者、广播接收者


应用场景

  • Android不同组件间的通信(含 :应用内 / 不同应用之间)
  • 多线程通信
  • Android 系统在特定情况下的通信

 比如今天的例子:时间变化监听、开启启动完成监听、网络变化监听


知识点1:静态注册广播

        动态注册的BroadcastReceiver可以自由地控制注册与注销,在灵活性方面有很大的优势。但是它存在着一个缺点,即必须在程序启动之后才能接收广播,因为注册的逻辑是写在onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下也能接收广播呢?这就需要使用静态注册的方式了。

        由于大量恶意的应用程序利用这个机制在程序未启动的情况下监听系统广播,从而使任何应用都可以频繁地从后台被唤醒,严重影响了用户手机的电量和性能,因此Android系统几乎每个版本都在削减静态注册BroadcastReceiver的功能。在Android 8.0系统之后,所有隐式广播都不允许使用静态注册的方式来接收了。

        静态注册实现开机启动,出了创建内部类,还可以通过Android Studio提供的快捷方式来创建。右击com.example.broadcasttest包→New→Other→Broadcast Receiver,会弹出如图所示的窗口。

 然后修改BootCompleteReceiver中的代码,如下所示:

class MyReceiver : BroadcastReceiver() {

    @SuppressLint("UnsafeProtectedBroadcastReceiver")
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "开机广播", Toast.LENGTH_SHORT).show()
        //接收到广播打开当前程序
        context.startActivity(context.packageManager.getLaunchIntentForPackage(context.packageName))
    }
}

 代码非常简单,我们在onReceive中实现了打开当前应用;

        另外,静态的BroadcastReceiver一定要在AndroidManifest.xml文件中注册才可以使用。不过,由于我们是使用Android Studio的快捷方式创建的BroadcastReceiver,因此注册这一步已经自动完成了。打开AndroidManifest.xml文件瞧一瞧,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.kotlin_demo">

    <!-- 接收启动完成 -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Kotlindemo">
        ....
        <!-- 静态注册,开机启动广播 -->
        <receiver
            android:name=".Chapter5.MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

自动创建的MyReceiver是无法收到开机广播的,因为我们还需要对AndroidManifest.xml文件进行修改才行,如上所示,运行效果如下:

知识点2:动态注册广播

        动态广播最好在Activity 的 onResume()注册、onPause()注销,对于动态广播,有注册就必然得有注销,否则会导致内存泄露注册。

        在代码中调用registerReceiver()方法,具体代码如下:

    override fun onResume() {
        super.onResume()
        // 监听时间变化,通常一分钟跳一次时间
        time = TimeReceiver()
        val timeFilter = IntentFilter()
        timeFilter.addAction(Intent.ACTION_TIME_TICK)
        registerReceiver(time, timeFilter)
        // 监听网络变化
        netWork = NetworkReceiver()
        val networkFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        registerReceiver(netWork, networkFilter)
    }

    override fun onPause() {
        super.onPause()
        //页面关闭,停止广播
        unregisterReceiver(time)
        unregisterReceiver(netWork)
    }

    inner class TimeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Toast.makeText(context, "时间被监听", Toast.LENGTH_SHORT).show()
            Log.i("TAG", "TimeReceiver: 时间被监听")
        }
    }

    inner class NetworkReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            Log.i("TAG", "NetworkReceiver: 网络被监听")

            val manager =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = manager.activeNetworkInfo

            // 判断网络情况
            if (networkInfo != null && networkInfo.isAvailable) {
                // 网络可用时的执行内容
                Toast.makeText(context, "网络可用", Toast.LENGTH_SHORT).show()
            } else {
                // 网络不可用时的执行内容
                Toast.makeText(context, "network connect fail", Toast.LENGTH_SHORT).show()
            }
        }
    }

效果如下:


知识点3:自定义全局广播

        实现全局通知消息广播,点击确认退出程序的功能。

        由于BroadcastReceiver中需要弹出一个对话框来阻塞用户的正常操作,但如果创建的是一个静态注册的BroadcastReceiver,是没有办法在onReceive()方法里弹出对话框这样的UI控件的,而我们显然也不可能在每个Activity中都注册一个动态的BroadcastReceiver。那么到底应该怎么办呢?答案其实很明显,只需要在BaseActivity中动态注册一个BroadcastReceiver就可以了,因为所有的Activity都继承自BaseActivity。

先创建一个ActivityCollector类用于管理所有的Activity,代码如下所示:

object ActivityCollector {

    private val activityList = ArrayList<Activity>()

    //添加activity到集合
    fun addActivity(activity: Activity) {
        activityList.add(activity)
    }

    //从集合里面移除
    fun removeActivity(activity: Activity){
        activityList.remove(activity)
    }

    //关闭所有activity
    fun finishAll(){
        for (activity in activityList){
            if (!activity.isFinishing){
                activity.finish()
            }
        }
        activityList.clear()
    }
}

然后创建BaseActivity类作为所有Activity的父类,代码如下所示:

open class BaseActivity : AppCompatActivity() {

    private lateinit var text: TextReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.i("BaseActivity", javaClass.simpleName)
        //添加activity
        ActivityCollector.addActivity(this)
    }

    override fun onResume() {
        super.onResume()
        text = TextReceiver()
        val textFilter = IntentFilter("com.example.kotlin_demo.TextReceiver")
        registerReceiver(text, textFilter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(text)
    }

    inner class TextReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            AlertDialog.Builder(context)
                .setTitle("消息提醒")
                .setMessage("这是一条全局广播,点我退出应用")
                .setPositiveButton("确定") { _, _ ->
                    ActivityCollector.finishAll()
                }
                .setNeutralButton("取消", null)
                .create()
                .show()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        //销毁activity
        ActivityCollector.removeActivity(this)
    }
}

然后通过一个按钮用于触发自定义广播。如下所示:

    //3、在BaseActivity,自定义一条全局广播,推送一条消息
    val butSend :AppCompatButton = findViewById(R.id.but_send)
    butSend.setOnClickListener {
        //任意地方可主动发起广播
        val intent = Intent("com.example.kotlin_demo.TextReceiver")
        sendBroadcast(intent)
    }

运行效果如下:

        因为我们始终需要保证只有处于栈顶的Activity才能接收到这条强制下线广播,非栈顶的Activity不应该也没必要接收这条广播,所以写在onResume()和onPause()方法里就可以很好地解决这个问题,当一个Activity失去栈顶位置时就会自动取消BroadcastReceiver的注册。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Kotlin 的 Fragment 中使用动态广播可以按照以下步骤进行: 1. 注册广播接收器 在 Fragment 中,可以通过 `requireActivity()` 方法获取到所在的 Activity,然后调用 `registerReceiver()` 方法注册广播接收器。如下所示: ```kotlin val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { // 处理接收到的广播 } } val filter = IntentFilter("com.example.ACTION") requireActivity().registerReceiver(receiver, filter) ``` 上述代码中,我们创建了一个名为 `receiver` 的匿名内部类,继承自 `BroadcastReceiver` 类,并实现了 `onReceive()` 方法来处理接收到的广播。然后,创建了一个名为 `filter` 的 `IntentFilter` 对象,用于指定所要接收的广播类型。最后,调用 `requireActivity().registerReceiver(receiver, filter)` 方法注册广播接收器。 2. 取消广播接收器 在 Fragment 销毁时,需要取消广播接收器的注册,以避免内存泄漏。可以在 `onDestroy()` 方法中调用 `requireActivity().unregisterReceiver(receiver)` 方法取消注册。完整代码如下所示: ```kotlin class MyFragment : Fragment() { private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { // 处理接收到的广播 } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // 创建视图 } override fun onResume() { super.onResume() val filter = IntentFilter("com.example.ACTION") requireActivity().registerReceiver(receiver, filter) } override fun onDestroy() { super.onDestroy() requireActivity().unregisterReceiver(receiver) } } ``` 上述代码中,我们将广播接收器的创建、注册和取消注册分别放在了 `onCreateView()`、`onResume()` 和 `onDestroy()` 方法中。这样做可以确保广播接收器的生命周期与 Fragment 的生命周期保持一致。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

peacejay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值