Implement Eclipse MQTT Android Client using single connection instance

android, java, mqtt, paho

Solution

A 'better' way would be to create a `Service` which connects/reconnects to the MQTT Broker.

I created my own service called `MqttConnectionManagerService` which maintains and manages connection to the broker.

Key features of this solution:

- Service maintains a single instance as long as it is alive.

- If service is killed, Android restarts it (because `START_STICKY`)

- Service can be started when device boots.

- Service runs in the background and is always connected to receive notifications.

- If the service is alive, calling `startService(..)` again would trigger its `onStartCommand()` method (and not `onCreate()`). In this method, we simply check if this client is connected to the broker and connect/reconnect if required.

Sample code:

MqttConnectionManagerService

public class MqttConnectionManagerService extends Service {

    private MqttAndroidClient client;
    private MqttConnectOptions options;

    @Override
    public void onCreate() {
        super.onCreate();
        options = createMqttConnectOptions();
        client = createMqttAndroidClient();
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.connect(client, options);
        return START_STICKY;
    }

    private MqttConnectOptions createMqttConnectOptions() {
        //create and return options
    }

    private MqttAndroidClient createMqttAndroidClient() {
        //create and return client
    }

    public void connect(final MqttAndroidClient client, MqttConnectOptions options) {

        try {
            if (!client.isConnected()) {
                IMqttToken token = client.connect(options);
                //on successful connection, publish or subscribe as usual
                token.setActionCallback(new IMqttActionListener() {..});
                client.setCallback(new MqttCallback() {..});
            }
        } catch (MqttException e) {
            //handle e
        }
    }

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="...">

    <!-- Permissions required to receive BOOT_COMPLETED event -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!-- activities go here -->

        <!-- BroadcastReceiver that starts MqttConnectionManagerService on device boot -->
        <receiver android:name=".MqttServiceStartReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <!-- Services required for using MQTT -->
        <service android:name="org.eclipse.paho.android.service.MqttService" />
        <service android:name=".MqttConnectionManagerService" />
    </application>

</manifest>

MqttServiceStartReceiver

public class MqttServiceStartReceiver extends BroadcastReceiver {    
    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, MqttConnectionManagerService.class));
    }
}

In your Activity's `onResume()`

startService(new Intent(this, MqttConnectionManagerService.class));

Problem

I am using Eclipse Paho android mqtt service in my app. I am able to subscribe and publish the messages to mqtt broker. I have couple of Activities in the app, when any activity is started it connects to broker using `mqttAndroidClient.connect(null, new IMqttActionListener() {}` and gets the response in `mqttAndroidClient.setCallback(new MqttCallback() {}`. My questions: - Is this the correct way to implement the android mqtt service ? - Is there a way to use same connection and callback instance throughout the app ?

Original source