2

I use pahoo mqtt on android side and implement it on flutter to make it run when the app was closed. However the client are still connected and still get the message from brokker after i close the app. But when i open the app again it seems it failed to invoke method from android side when message is arrive mBackgroundChannel.invokeMethod("mqttMessageArrive", strMessage) and get this warning message Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: com.example.research_cahyo/method_dart. Response ID: 0.

I also got this error after i close the app

2020-06-18 17:27:16.751 27939-27939/com.example.research_cahyo E/ActivityThread: Activity com.example.research_cahyo.MainActivity has leaked ServiceConnection org.eclipse.paho.android.service.MqttAndroidClient$MyServiceConnection@4c11377 that was originally bound here
    android.app.ServiceConnectionLeaked: Activity com.example.research_cahyo.MainActivity has leaked ServiceConnection org.eclipse.paho.android.service.MqttAndroidClient$MyServiceConnection@4c11377 that was originally bound here
        at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1813)
        at android.app.LoadedApk.getServiceDispatcherCommon(LoadedApk.java:1685)
        at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:1664)
        at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1732)
        at android.app.ContextImpl.bindService(ContextImpl.java:1661)
        at android.content.ContextWrapper.bindService(ContextWrapper.java:715)
        at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:425)
        at com.example.research_cahyo.mqtt.MQTTConnection.doConnect(MqttConnection.kt:32)
        at com.example.research_cahyo.MyPlugin.doStartMqttService(MyPlugin.kt:69)
        at com.example.research_cahyo.MyPlugin.onMethodCall(MyPlugin.kt:149)
        at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:231)
        at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:93)
        at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:642)

Bellow this is my mainactivity.kt

class MainActivity : FlutterActivity() {

    private val TAG = "MAIN ACTIVITY";

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(Intent(activity.applicationContext, NotificationService::class.java))
            } else {
                startService(Intent(activity.applicationContext, NotificationService::class.java))
            }

            GeneratedPluginRegistrant.registerWith(flutterEngine);
            Storage.initValue(this.applicationContext)

            val binaryMessenger = flutterEngine.getDartExecutor().getBinaryMessenger()
            MethodChannel(binaryMessenger, INVOKE_METHOD_ANDROID)
                    .setMethodCallHandler(MyPlugin(this, binaryMessenger))
    }
}

and this is myplugin.kt

class MyPlugin(private val activity: Activity, binaryMessenger: BinaryMessenger) : MethodChannel.MethodCallHandler, IMqttCallback {

    private var mBackgroundChannel: MethodChannel

    private lateinit var subscribeTopic: String

    init {
        mBackgroundChannel = MethodChannel(binaryMessenger, INVOKE_METHOD_DART)
    }

    fun onPublishMessage(call: MethodCall, rawResult: MethodChannel.Result) {
        val params = call.arguments<Map<String, String>>()

        if (params.containsKey("messages") && params.containsKey("topic")) {
            val messages = params["messages"] ?: ""
            val topic = params["topic"] ?: ""

            MQTTConnection.instance?.doPublishMessages(messages, topic)

            rawResult.success(true)
        } else {
            rawResult.error("INCOMPLETE ARGS", "ARGUMEN ARE INCOMPLETE", null);
        }
    }

    fun doCheckMqttStatus(result: MethodChannel.Result) {
        result.success(MQTTConnection.instance?.isConnected)
    }

    fun doUnSubscribeTopic(call: MethodCall, result: MethodChannel.Result) {
        val param: Map<String, String> = call.arguments();
        val topic: String = param.get("topic") ?: ""

        if (topic.isNotEmpty()) {
            MQTTConnection.instance?.doUnSubscribeTopic(topic, this)
        }
    }

    fun doStartMqttService(call: MethodCall, result: MethodChannel.Result) {
        val param: Map<String, String> = call.arguments();
        val serverUri: String = param.get("serverUri") ?: ""
        val clientId: String = param.get("clientId") ?: ""
        val clientUsername: String = param.get("clientUsername") ?: ""
        val clientPassword: String = param.get("clientPassword") ?: ""
        subscribeTopic = param.get("subscribeTopic") ?: ""

        val valid = serverUri.length > 0 && clientId.length > 0 &&
                clientUsername.length > 0 && clientPassword.length > 0 &&
                subscribeTopic.length > 0

        if (valid) {
            Storage.saveValue(MQTTOPTIONS_STORAGE_KEY, "$serverUri,$clientId,$clientUsername,$clientPassword,$subscribeTopic")
        }

        if (valid && !(MQTTConnection.instance?.isConnected ?: false)) {
            MQTTConnection.instance?.doConnect(activity, serverUri, clientId, clientUsername, clientPassword, this)
            result.success("Start mqtt invoked")
        } else {
            result.error("Invalid Arguments", "Mqtt failed to invoked", null)
        }
    }

    fun doStopMqttService(result: MethodChannel.Result) {
        MQTTConnection.instance?.doDisConnect(true)
        result.success("Stop mqtt invoked")
    }

    fun onGetNotifications(result: MethodChannel.Result) {
        val listMessage = (Storage.getValue(NOTIFICATION_STORAGE_KEY) as List<*>).map { it.toString() }
        result.success(listMessage)
    }

    fun onSetNotification(call: MethodCall, result: MethodChannel.Result) {
        try {
            val params = (call.arguments() as List<*>).map { it.toString() };
            Storage.saveValue(NOTIFICATION_STORAGE_KEY, params)
        } catch (e: Exception) {
            result.error("Set storage error", "Set Notification Error", null);
        }
    }

    override fun onMQTTConnectionSuccess() {
        if (!(MQTTConnection.instance?.hasTopic(subscribeTopic) ?: false)) {
            MQTTConnection.instance?.doSubscribeTopic(subscribeTopic, this)
        }
    }

    override fun onMQTTSubscribeTopicSuccess() {
        MQTTConnection.instance?.doMessageListen(this)
    }

    override fun onMQTTSubscribeTopicFailed(messages: String?) {
        mBackgroundChannel.invokeMethod("mqttSubscribeFailed", messages)
    }

    override fun onMQTTConnectionFailed(messages: String?) {
        mBackgroundChannel.invokeMethod("mqttConnectFailed", messages)
    }

    override fun onMQTTMessagesArrived(mqttMessage: MqttMessage?) {
        mqttMessage?.let {
            val strMessage = String(it.payload)
            mBackgroundChannel.invokeMethod("mqttMessageArrive", strMessage)

            val listMessage = (Storage.getValue(NOTIFICATION_STORAGE_KEY) as MutableList<*>).map {
                it.toString()
            }.toMutableList()
            listMessage.add(strMessage)
            Storage.saveValue(NOTIFICATION_STORAGE_KEY, listMessage)

            Log.d(TAG, "message has arrived")
            val notificationBuilder = NotificationCompat.Builder(activity.applicationContext, Constant.CHANNEL_ID)
            notificationBuilder.setSmallIcon(R.drawable.ic_launcher_foreground)
                    .setContentTitle("Message")
                    .setContentText(strMessage)
                    .setVibrate(arrayListOf(1000L, 1000L, 1000L, 1000L).toLongArray())
            val notification = notificationBuilder.build()

            with(NotificationManagerCompat.from(activity.applicationContext)) {
                this.notify(Random.nextInt(0, 100), notification)
            }
        }
    }

    override fun onMQTTUnsubscribeSuccess() {
        mBackgroundChannel.invokeMethod("mqttUnsubscribeSuccess", "Mqtt unsubscribe success")
    }

    override fun onMQTTUnsubscribeFailed() {
        mBackgroundChannel.invokeMethod("mqttUnsubscribeFailed", "Mqtt unsubscribe failed")
    }

    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
        when (call.method) {
            "publishMessage" -> onPublishMessage(call, result)
            "startMqttService" -> doStartMqttService(call, result)
            "stopMqttService" -> doStopMqttService(result)
            "checkMqttStatus" -> doCheckMqttStatus(result)
            "unsubscribeTopic" -> doUnSubscribeTopic(call, result)
            "getNotification" -> onGetNotifications(result)
            "setNotification" -> onSetNotification(call, result)
            else -> result.notImplemented()
        }
    }
}

can anyone solve this,,, sorry for bad english

cahyowhy
  • 553
  • 2
  • 9
  • 26

0 Answers0