Search code examples
androidandroid-activitykotlininterfacebroadcastreceiver

Interface reference is null even after it got initialized making me unable to show snackbar when internet connection changes


I'm implementing BroadcastReceiver to show Snackbar when internet connection changes, so i created an interface and initialized it in 3 different activities to execute snackbar code when internet connection changes

My problem is that the interface reference in the 2nd and 3rd activity is null but not null in the 1st activity strangely

i thought the problem might be that i use the same interface reference for all the three activities (I was kind of sure that this isn't the problem but i was thinking that something was going on that i don't know of) so i created 3 different references, one for each activity but this still didn't solve my problem

BroadcastReceiver code:

class NetworkChangeReceiver : BroadcastReceiver() {

    private var firstActivityReference: InternetSnackbarInterface? = null
    private var secondActivityReference: InternetSnackbarInterface? = null
    private var thirdActivityReference: InternetSnackbarInterface? = null

    fun registerFirstActivityInterface(snackbarInterface: InternetSnackbarInterface) {
        this.firstActivityReference= snackbarInterface
    }

    fun registerSecondActivityInterface(snackbarInterface: InternetSnackbarInterface) {
        this.secondActivityReference= snackbarInterface
    }

    fun registerThirdActivityInterface(snackbarInterface: InternetSnackbarInterface) {
        this.thirdActivityReference= snackbarInterface
    }

    override fun onReceive(context: Context, intent: Intent?) {

        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetworkInfo = connectivityManager.activeNetworkInfo
        val isConnected = activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting
        if (isConnected){
            firstActivityReference?.hideNoInternetSnackbar()
            secondActivityReference?.hideNoInternetSnackbar()
            thirdActivityReference?.hideNoInternetSnackbar()

        }else{
            firstActivityReference?.showNoInternetSnackbar("No internet connection")
            secondActivityReference?.showNoInternetSnackbar("No internet connection")
            thirdActivityReference?.showNoInternetSnackbar("No internet connection")


        }
    }

    interface InternetSnackbarInterface {
        fun showNoInternetSnackbar(message: String)
        fun hideNoInternetSnackbar()
    }

}

first activity related code:

class FirstActivity: AppCompatActivity(),NetworkChangeReceiver.InternetSnackbarInterface{
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

         val networkChangeReceiver = NetworkChangeReceiver()
         networkChangeReceiver.registerFirstActivityInterface(this)
        val intentFilter = IntentFilter()
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE")
        registerReceiver(networkChangeReceiver,intentFilter)
   }

    var internetSnackbar : Snackbar? =null
    private fun showSnackbar(message : String,length : Int){
        val parentLayout = findViewById<View>(android.R.id.content)
        internetSnackbar = Snackbar.make(parentLayout, message, length)
        internetSnackbar?.show()

    }

    override fun hideNoInternetSnackbar() {
        internetSnackbar?.dismiss()
    }

    override fun showNoInternetSnackbar(message: String) {
        showSnackbar(message, Snackbar.LENGTH_INDEFINITE)
    }

}

second activity related code:


class SecondActivity: AppCompatActivity(),NetworkChangeReceiver.InternetSnackbarInterface{
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

         val networkChangeReceiver = NetworkChangeReceiver()
         networkChangeReceiver.registerSecondActivityInterface(this)
   }

    var internetSnackbar : Snackbar? =null
    private fun showSnackbar(message : String,length : Int){
        val parentLayout = findViewById<View>(android.R.id.content)
        internetSnackbar = Snackbar.make(parentLayout, message, length)
        internetSnackbar?.show()

    }

    override fun hideNoInternetSnackbar() {
        internetSnackbar?.dismiss()
    }

    override fun showNoInternetSnackbar(message: String) {
        showSnackbar(message, Snackbar.LENGTH_INDEFINITE)
    }

}

third activity related code:

class ThirdActivity: AppCompatActivity(),NetworkChangeReceiver.InternetSnackbarInterface{
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

         val networkChangeReceiver = NetworkChangeReceiver()
         networkChangeReceiver.registerThirdActivityInterface(this)
   }

    var internetSnackbar : Snackbar? =null
    private fun showSnackbar(message : String,length : Int){
        val parentLayout = findViewById<View>(android.R.id.content)
        internetSnackbar = Snackbar.make(parentLayout, message, length)
        internetSnackbar?.show()

    }

    override fun hideNoInternetSnackbar() {
        internetSnackbar?.dismiss()
    }

    override fun showNoInternetSnackbar(message: String) {
        showSnackbar(message, Snackbar.LENGTH_INDEFINITE)
    }

}

with some debugging i found out that:

right when registerSecondActivityReference is called the referene is not null but right after that it's null again and the same with the thirdActivityReference knowing that i never assign them to null again in any part of my code

strangely this never happen to firstActivityReference

and sorry for any inconsistency this is my first question here.


Solution

  • Change this -- class NetworkChangeReceiver : BroadcastReceiver() { to -- object NetworkChangeReceiver : BroadcastReceiver() {

    and change this -- val networkChangeReceiver = NetworkChangeReceiver() to -- val networkChangeReceiver = NetworkChangeReceiver

    Reason:

    You are creating a new instance in each activity with this line val networkChangeReceiver = NetworkChangeReceiver()

    and registering only first activity using this code

    val intentFilter = IntentFilter()
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE")
        registerReceiver(networkChangeReceiver,intentFilter)
    

    Solution: Make broadcast receiver singleton using object keyboard.