How to call MainActivity from BroadCastReciever


#1

I’ve a BroadcastReceive and want to change/display the text of the views in the MainActivity based on the logic in the broadcast

class Receiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
         // somthing like
        // MainActivity.layout.latitudeTxt = ....
   }
}

My MainActivity is as below:

private lateinit var layout: View
private lateinit var latitudeTxt: TextView
private lateinit var longitudeTxt: TextView

class MainActivity : AppCompatActivity() {

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

        layout = main_layout
        latitudeTxt = latitudeText
        longitudeTxt = longitudeText
    }
}

#2

You can’t call a method on a MainActivity instance when you are not sure there is one currently running.

Either you register/unregister the BroadcastReceiver in your onResume/onPause in which case you can safely pass a reference to the current instance of your MainActivity to your Receiver instance without risking Context leak (since Receiver would be tied to your MainActivity’s lifecycle). It would looks a bit like :

override fun onResume() {
//...
val r = Receiver(this)
...
this.registerReceiver(r, filter)
...
}

(see here -> Context-registered receivers)

Or you have your receiver registered in AndroidManifest.xml, in which case you can :

  • Fire and forget an Intent to the MainActivity that will be dropped if MainActivity is not running (in which case you need to create a receiver in your MainActivity somewhat like described here)
  • Implement a registration system where your MainActivity would check in and out of the Receiver in its onResume/onPause : In this case you know in the receiver if there is a currently running instance of MainActivity and can decide what to do without leaking Context.

#3

Thanks, mm, what about if I need the receiver to keep running regardless the active activity, and its response to be varies based on the active activity itself! Is there a way that I can detect the active activity from my , something like:

class Receiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
         // check the active activity
         // if MainActivity then ....
         // if OtherActivity then ...
   }
}

#4

Not sure if it is the best way of implementing it but it could look a bit like

class Receiver : BroadcastReceiver() {
    var activity : Activity? = null
    override fun onReceive(context: Context, intent: Intent) {
        when (activity) {
            is MainActivity -> // do something
            is XXXActivity -> // do something else
            else -> // put in cache ?
        }
    }
}

And then you’d call receiver.activity = this in your onResume and receiver.activity = null in your onPause.

Obviously this is just a small stub you can use as a start i did not take into account the possibility to have multiple activities registered at the same time or accessing the activity property from multiple threads, but that could be the general idea of how to do it.


#5

Thanks @vb, but I could not call it from the mainactivity, I got error at the below line “unresolved reference: activity”


#6

Not sure where this could come from, check your imports maybe ? Make sure receiver is of type Receiver and not BroadcastReceiver ? It’s difficult to guess where this could come from.