0

Whenever I encounter an error in the paho MQTT client, I attempt a reconnect 60 seconds later:

override fun connectionLost(cause: Throwable) {
    LOG.e("Connection Lost :: $cause")
    cleanupClient()
    retry { connect() }
}

private fun cleanupClient(){
    try {
        for (i in topicList.indices) {
            client!!.unsubscribe(topicList[i])
        }
        client!!.close()
        client = null
    } catch (e: Exception) {
        LOG.e("Could not clean up!", e)
    }
}

fun retry(cb: () -> Unit){
    handler.removeCallbacksAndMessages(null)
    handler.postDelayed({
        cb()
    }, 60000)
}

So if the app is sitting without internet, it will continuously attempt to reconnect until it finally does. The issue is that after a few hundred attempts (a couple hours), the app crashed with an Out of Memory Issue:

java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack available

I only have 2 class-global variables, my handler and my MqttAndroidClient:

private var client: MqttAndroidClient? = null

// For retries
val handler = Handler()

And of those, only the client is ever re-assigned a value. My understanding is that in the clean up function, because I close and null out the client, the JVM should clean up my resources. The documentation for client.close():

Close the client. Releases all resource associated with the client. After the client has been closed it cannot be reused. For instance attempts to connect will fail.

There is also another function called unregisterResources()

Unregister receiver which receives intent from MqttService avoids IntentReceiver leaks.

It seems to me that only client.close() needs to be called, but I'm unsure if this will cause other issues.

And if there is anything else that you would suggest that I look at, I would love your advice!

Code Wiget
  • 1,540
  • 1
  • 23
  • 35
  • Why do this manually when the Paho Android service will do reconnection for you? – hardillb Feb 08 '20 at 15:18
  • Their auto-reconnect doesn't work right and it doesn't auto re-subscribe, so i need to handle it anyways – Code Wiget Feb 08 '20 at 15:33
  • Here is another post saying something similar - implement your own reconnect logic: https://stackoverflow.com/questions/33735090/java-eclipse-paho-implementation-auto-reconnect – Code Wiget Feb 08 '20 at 16:22
  • That is 4 years old (things change) and also nothing to do with Android – hardillb Feb 08 '20 at 16:24

1 Answers1

0

Somewhere internally in the client, there is a memory leak. So re-creating the client each time there is an issue will eventually cause your app to crash, regardless of if you use close.

When I built the app this way, I went off of this answer on SO(Java Eclipse Paho Implementation - Auto reconnect). As @hardillb pointing out, this is now outdated. Instead, use the reconnect callback:

conOpt.isAutomaticReconnect = true

implement MqttCallbackExtended on your class:

class NotificationService : Service(), MqttCallbackExtended {

And then implement connectComplete() override fun connectComplete(unusedArg1: Boolean, unusedArg2: String?) {

LOG.i("Connection completed!")
        try{
            subscribe()
        } catch(e: java.lang.Exception){
            LOG.e("Unable to re-subscribe", e)
        }
    }
Code Wiget
  • 1,540
  • 1
  • 23
  • 35