Paho MQTT Android Service Issue

后端 未结 4 1698
离开以前
离开以前 2020-12-30 11:56

I am implementing the Paho MQTT Android Service within an application I am developing. After testing the sample application provided by Paho, I have found that there are a f

4条回答
  •  感动是毒
    2020-12-30 12:15

    While this doesn't seem like a complete solution to the problem I will post my workaround in case it helps someone.

    For me the problem begins when the user swipes the app out of the recent apps list. As mentioned here such an action not only kills the activity, instead it kills the whole process, including the MqttService. Then as mentioned in the thread Android recognizes that your service should be restarted and schedules a restart of the killed service. However, this doesn't imply connection recovery as all connections were bound to the activity.

    So unless you find out a way to eliminate the service stopping issue you are guaranteed to lose connection to the broker when the user decides to swipe out the app.

    This is not the end of the world however, as we can simply reconnect after we've lost connection. The problem is, this time we don't have an activity to do the desired action. You have to either amend the source code of the Paho Android service library, or in a much simpler fashion what I did was to create another service.

    All the connections will take place in this new service, and any activities wishing to connect should communicate with this service. The advantage of this is we can make the service sticky and even if the user swipes our app and kills it, it will immediately restart and we can recover by simply reconnecting.

    So as a demonstration with this very simple service:

    public class MessagingService extends Service {
        private static final String TAG = "MessagingService";
        private MqttAndroidClient mqttClient;
        String deviceId;
    
    
    
        @Override
        public void onCreate() {
        }
        private void setClientID() {
            WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            WifiInfo wInfo = wifiManager.getConnectionInfo();
            deviceId = wInfo.getMacAddress();
            if (deviceId == null) {
                deviceId = MqttAsyncClient.generateClientId();
            }
        }
    
        public class MsgBinder extends Binder {
            public MsgServ getService() {
                return MsgServ.this;
            }
        }
    
        public void doConnect(){
            // Using some of the Paho sample app classes
            String server = ConfigClass.BROKER_URI;
            MemoryPersistence mem = new MemoryPersistence();
            mqttClient = new MqttAndroidClient(this,ConfigClass.BROKER_URI,deviceId,mem);
            MqttConnectOptions conOpt = new MqttConnectOptions();
            String clientHandle = server + deviceId;
            Connection con = new Connection(clientHandle, deviceId, ConfigClass.BROKER_ADDRESS,
                                            ConfigClass.BROKER_PORT, this, mqttClient, false);
            conOpt.setCleanSession(false);
            conOpt.setConnectionTimeout(ConfigClass.CONN_TIMEOUT);
            conOpt.setKeepAliveInterval(ConfigClass.CONN_KEEPALIVE);
            conOpt.setUserName("testclient");
            conOpt.setPassword("password".toCharArray());
            String[] actionArgs = new String[1];
            actionArgs[0] = deviceId;
            final ActionListener callback =
                    new ActionListener(this, ActionListener.Action.CONNECT, clientHandle,
                                       actionArgs);
            mqttClient.setCallback(new MqttCallbackHandler(this, clientHandle));
            mqttClient.setTraceCallback(new MqttTraceCallback());
            con.addConnectionOptions(conOpt);
            Connections.getInstance(this).addConnection(con);
            try {
                mqttClient.connect(conOpt, null, callback);
                Log.d("Con", "Connected");
            } catch (MqttException e) {
                Log.d("Con", "Connection failed");
                e.printStackTrace();
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            doConnect();
            return START_STICKY;
        }
    
    }
    

    Log of server:

    1433455371: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient').
    1433455371: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0)
    1433455375: Socket error on client ed:0a:2b:56:b5:45, disconnecting.
    1433455377: New connection from 192.168.2.5 on port 1883.
    1433455377: Client ed:0a:2b:56:b5:45 disconnected.
    1433455377: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient').
    1433455377: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0)
    

    As you can see as soon as I close the app and the service gets killed, it restarts reconnects and gets kept-alive just find afterwards. From here, you should be able to do the rest. Perhaps creating a notification with your newly arrived message which will open the app. Just remember to do everything in the newly created service which is guaranteed to maintain a connection.

提交回复
热议问题