【问题标题】:Kotlin: Call a function to update UI from BroadcastReceiver onReceiveKotlin:调用函数以从 BroadcastReceiver onReceive 更新 UI
【发布时间】:2018-05-24 08:37:05
【问题描述】:

我是 Kotlin 的新手,它看起来很棒!虽然今天,我一直在尝试用 Java 做一些超级简单的事情,但我完全陷入了困境。

我正在使用广播接收器来确定设备何时连接/断开电源。我需要做的就是相应地更新我的 UI。


我的代码

这是我的BroadcastReceiver 课程,它似乎工作正常。

class PlugInReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action

        if (action == Intent.ACTION_POWER_CONNECTED) {
            // Do stuff when power connected
        } 
        else if (action == Intent.ACTION_POWER_DISCONNECTED) {
            // Do more stuff when power disconnected
        }
    }
}

现在在我的MainActivity(但在其他地方,稍后)中,我想在触发意图时更新我的​​ UI,例如在下面的函数中,背景颜色会发生变化。

private fun updateBackgroundColor( newBgColorId: Int = R.color.colorAccent){
    val mainLayout = findViewById<View>(R.id.mainLayout)
    val colorFade = ObjectAnimator.ofObject(
            mainLayout, "backgroundColor", ArgbEvaluator(), oldBgColor, newBgColor)
    colorFade.start()
}

问题

如何在 MainActivity 上调用函数,或在 BroadcastReceiver 触发事件时更新我的​​ UI?


到目前为止我已经尝试过什么

  • 我研究了在某个地方有一个静态变量,存储 BroadcastReciever 的结果,然后是我的 UI 类中的一个 observable,相应地观察和调用适当的函数。虽然在谷歌搜索如何做到这一点之后,看起来这在 Kotlin 中并不是一个好方法。

  • 考虑尝试在 UI 线程上运行 BroadcastReciever,但这听起来很糟糕。

  • 尝试将 Java 实现与我的 Kotlin 类混合,但无法正常工作。

令人沮丧的是,我在 SO 上发现了几个非常相似的问题。然而,它们的实现似乎都使用了 Java 特有的特性:


我敢肯定,对于大多数 Android 开发人员来说,这是一个微不足道的问题,但我迷路了!如果您需要更多详细信息,请告诉我。提前非常感谢!

【问题讨论】:

    标签: android broadcastreceiver kotlin


    【解决方案1】:

    分享信息以在 Kotlin 中注册 BroadcastReceiver

    步骤 1. 在 MainActivity.kt 中创建 BroadcastReceiver

    private val mPlugInReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                Intent.ACTION_POWER_CONNECTED -> {
                    //update your main background color
                    updateBackgroundColor()
                }
                Intent.ACTION_POWER_DISCONNECTED -> {
                    //update your main background color
                    updateBackgroundColor()
                }
            }
        }
    }
    

    步骤 2. 创建 IntentFilter

    private fun getIntentFilter(): IntentFilter {
        val iFilter = IntentFilter()
        iFilter.addAction(Intent.ACTION_POWER_CONNECTED)
        iFilter.addAction(Intent.ACTION_POWER_DISCONNECTED)
        return iFilter
    }
    

    步骤 3. 在 onStart() 注册接收器

    override fun onStart() {
        super.onStart()
        registerReceiver(mPlugInReceiver, getIntentFilter())
    }
    

    步骤 4. 在 onStop() 取消注册接收器

    override fun onStop() {
        super.onStop()
        unregisterReceiver(mPlugInReceiver)
    }
    

    如果您有自定义广播接收器,您可以使用LocalBroadcastManager 注册并创建您的本地IntentFilter

    private val mLocalBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                AnyService.UPDATE_ANY -> {
    
                }
            }
        }
    }
    
    private fun getLocalIntentFilter(): IntentFilter {
        val iFilter = IntentFilter()
        iFilter.addAction(AnyService.UPDATE_ANY)
        return iFilter
    }
    

    注册本地接收器 LocalBroadcastManager.getInstance(applicationContext).registerReceiver(mLocalBroadcastReceiver, getLocalIntentFilter())

    注销本地接收者LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(mLocalBroadcastReceiver)

    【讨论】:

    • 如果广播接收器是一个单独的文件,我如何更新用户界面
    • 我不知道你是否会看到这个 zzas11 谢谢。我一直在寻找解决方案将近一个星期,现在我可以正常呼吸了。谢谢!
    【解决方案2】:

    实现这一点的最佳方法是在 BroadcastReceiver 中创建一个抽象方法,当调用 onReceive() 方法时,您可以调用将由您的 Activity 实现的该方法。

    BroadcastReceiver 示例:

    abstract class ConnectionBroadcastReceiver : BroadcastReceiver() {
    
    override fun onReceive(context: Context, intent: Intent) {
         //Do the checks or whatever you want
         var isConnected = true
    
        broadcastResult(isConnected)
    }
    
    protected abstract fun broadcastResult(connected: Boolean)
    

    }

    还有您活动中的代码(例如在 onCreate 或 onStart 中)。在这里,您将广播接收器注册到方法实现中,在这里您可以更新 UI:

        var connectionBroadcastReceiver = object : ConnectionBroadcastReceiver() {
            override fun broadcastResult(connected: Boolean) {
                if(isConnected){
                    refreshList()
                }
            }
        }
        val intentFilter = IntentFilter()
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
        this.registerReceiver(connectionBroadcastReceiver, intentFilter)
    

    不要忘记在 (onPause||onStop||onDestroy) 中取消注册接收器,但这不是绝对必要的。

    【讨论】:

      【解决方案3】:

      onReceive(...) 方法在主线程上运行。您可以在 onStart() 中注册您的 Activity,并在 onStop() 中取消注册,这将保证您的 UI 在收到事件时存在。

      【讨论】:

      • 感谢您的回答,但就其本身而言并没有多大意义(我是 Kotlin 的初学者)。您能否更详细地介绍一下在onStart() 中注册的具体内容以及如何仍然可以访问操纵 UI 的功能?
      • 那是在 Java 中,这就是问题所在...?
      • 你不能在同一个文件中混合使用 Kotlin 和 Java。您的类必须完全使用 Java 或完全使用 Kotlin。您可以在同一个项目中混合使用 Kotlin 和 Java 类,但不能在同一个类中混合使用 Java/Kotlin 代码。这是你问题的根源吗?
      • 我知道!!这就是我要说的——我的项目完全是 Kotlin,但你分享的链接是 Java!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多