Search code examples
androidkotlinandroid-lifecycleapplication-lifecycle

Proper way to unregister a callback from an Application class


I have implemented a custom Application class in my app which handles updating the app theme before the app start up.

I also registered a network callback to set a variable each time there is a connection change.

My application class is as such:

Application.kt

package com.th3pl4gu3.mes.ui

.....

class MesApplication : Application() {

    companion object {
        @Volatile
        private var INSTANCE: MesApplication? = null

        fun getInstance() =
            INSTANCE ?: synchronized(this) {
                INSTANCE
                    ?: MesApplication().also { INSTANCE = it }
            }
    }

    override fun onCreate() {
        super.onCreate()

        // Assigns 'this' to the singleton object
        INSTANCE = this

        // Updates the application's theme
        updateAppTheme()

        // Start a network callback to monitor internet connection
        startNetworkCallback()
    }

    private fun startNetworkCallback(){
        try{
            val cm = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val builder = NetworkRequest.Builder()

            cm.registerNetworkCallback(builder.build(), object: ConnectivityManager.NetworkCallback(){
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    Log.v("INTERNET_TEST", "AC: Network Available")
                    Global.isNetworkConnected = true
                }

                override fun onLost(network: Network) {
                    super.onLost(network)
                    Log.v("INTERNET_TEST", "AC: Network Lost")
                    Global.isNetworkConnected = false
                }
            })
            Global.isNetworkConnected = false
        }catch (e: Exception){
            Global.isNetworkConnected = false
        }
    }

}

However, from the docs, they recommend to unregister this callback but the Application class lifecycle doesn't have any onPause or onDestroy function.

Is there any proper way to unregister this callback to not cause any memory leaks?

Also feel free to suggest any alternatives in case I am coding this wrong


Solution

  • In this case , you can use ActivityLifecycleCallbacks, to detect are any Activity of your is in Foreground?

    ActivityLiveCycleListener

    class ActivityLiveCycleListener(private val appStateListener: AppStateListener) : Application.ActivityLifecycleCallbacks {
    
        companion object {
            var foregroundActivities = 0
        }
    
        override fun onActivityPaused(p0: Activity) {
    
        }
    
        override fun onActivityStarted(p0: Activity) {
            if(foregroundActivities == 0){
                appStateListener.onAppForeGround()
            }
            foregroundActivities++
        }
    
        override fun onActivityDestroyed(p0: Activity) {
    
        }
    
        override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
    
        }
    
        override fun onActivityStopped(p0: Activity) {
            foregroundActivities--
            if(foregroundActivities == 0){
                appStateListener.onAppBackground()
            }
        }
    
        override fun onActivityCreated(p0: Activity, p1: Bundle?) {
    
        }
    
        override fun onActivityResumed(p0: Activity) {
    
        }
    }
    

    And your interface can have two methods to indicate background/foreground state

    interface AppStateListener{
        fun onAppForeGround()
        fun onAppBackground()
    }
    

    Now in Application onCreate(), register to ActivityLifeCycleListener

    override fun onCreate(){
        registerActivityLifecycleCallbacks(ActivityLiveCycleListener(object : AppStateListener{
                override fun onAppForeGround() {
                    //start network listener
                }
    
                override fun onAppBackground() {
                    //remove network listener
                }
            }))
    }