4

I am new to Kotlin, and it seems awesome! Though today, I've been trying to do something that in Java was super simple, but I've got totally stuck.

I am using a broadcast receiver to determine when the device is connected/ disconnected from a power source. And all I need to do it update my UI accordingly.


My Code

Here's my BroadcastReceiver classs, and it seems to work fine.

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
        }
    }
}

Now in my MainActivity (but somewhere else, later on), I want to update my UI when the intent is fired, for example in the function below, the background color changes.

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()
}

The Question

How can I call a function on the MainActivity, or update my UI when the BroadcastReceiver fires an event?


What I've tried so far

  • I looked into having a static variable somewhere, storing the result of the BroadcastReciever, then an observable in my UI class, watching and calling appropriate function accordingly. Though after Googling how to do this, looks like that's not really a good approach in Kotlin.

  • Considered trying to run the BroadcastReciever on the UI thread, but that sounds like a terrible idea.

  • Tried mixing a Java implementation with my Kotlin class, but couldn't get it to work.

Frustratingly I found several very similar questions on SO. However their implementations seem to all use Java-specific features:


I'm sure this is a trivial question for most Android developers, but I am lost! Let me know if you need any more details. Thanks very much in advance!

Alicia Sykes
  • 5,997
  • 7
  • 36
  • 64

3 Answers3

3

Sharing the info to register BroadcastReceiver in Kotlin

Step 1. Create BroadcastReceiver in MainActivity.kt

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()
            }
        }
    }
}

Step 2. Create IntentFilter

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

Step 3. Register receiver at onStart()

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

Step 4. Unregister receiver at onStop()

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

If you have custom BroadcastReceiver, you can register using LocalBroadcastManager and create your local 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
}

Register local receiver LocalBroadcastManager.getInstance(applicationContext).registerReceiver(mLocalBroadcastReceiver, getLocalIntentFilter())

Unregister local receiver LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(mLocalBroadcastReceiver)

zzas11
  • 1,115
  • 9
  • 16
  • how do I update the ui if the broadcastreceiver is a separate file – Srishti Roy Jul 04 '18 at 07:45
  • I dont know if you ever going to see this zzas11 Thank you. i have been looking for solution for almost a week, now I can breath properly. Thank YOU! – Terry Oct 16 '21 at 02:55
2

The best way to achieve that is to create an abstract method in the BroadcastReceiver, and when onReceive() method is called, you can invoke that method that will be implemented by your activity.

BroadcastReceiver example:

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)

}

And the code in your activity (in the onCreate or onStart for example). Here you register the broadcast receiver with the method implementation, and here you can update the 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)

Don't forget to unregister the receiver in (onPause||onStop||onDestroy), but it's not strictly necessary.

Jaume Colom Ferrer
  • 559
  • 1
  • 5
  • 14
0

The onReceive(...) method runs on the main thread. You can register your Activity in onStart() and unregister it in onStop(), which will guarantee that your UI is present when the event is received.

C2H6O
  • 166
  • 2
  • 13
  • Thanks for your answer, but on it's own that doesn't really make a lot of sense (I'm a beginner with Kotlin). Could you go into any more detail, on specifically what to register in the `onStart()` and how that can still access functions that manipulate the UI? – Alicia Sykes Dec 10 '17 at 23:03
  • This should work for you: https://stackoverflow.com/questions/22241705/calling-a-activity-method-from-broadcastreceiver-in-android – C2H6O Dec 11 '17 at 02:11
  • That's in Java, which is what the issue was in the first place...? – Alicia Sykes Dec 11 '17 at 12:20
  • You can't mix Kotlin and Java in the same file. Your Class must either be fully in Java or fully in Kotlin. You can mix Kotlin and Java classes in the same project, but you can't have Java/Kotlin code intermixed in the same class. Was that the root of your question? – C2H6O Dec 12 '17 at 00:06
  • I know!! That's what I'm saying- my project is fully Kotlin, but the link you shared is Java! – Alicia Sykes Dec 12 '17 at 10:15