Android MQTT service – Code example

MQTT Service with MQTTCallback innerclass to handle messages

package com.simonecaruso.mqtt.service;
 
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 
import com.simonecaruso.mqtt.FullscreenActivityTest;
 
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
 
public class MQTTService extends Service {
 
    private static final String TAG = "MQTTService";
    private static boolean hasWifi = false;
    private static boolean hasMmobile = false;
    private Thread thread;
    private ConnectivityManager mConnMan;
    private volatile IMqttAsyncClient mqttClient;
    private String deviceId; 
 
    class MQTTBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            IMqttToken token;
            boolean hasConnectivity = false;
            boolean hasChanged = false;
            NetworkInfo infos[] = mConnMan.getAllNetworkInfo();
 
            for (int i = 0; i < infos.length; i++){
                if (infos[i].getTypeName().equalsIgnoreCase("MOBILE")){
                    if((infos[i].isConnected() != hasMmobile)){
                        hasChanged = true;
                        hasMmobile = infos[i].isConnected();
                    }
                    Log.d(TAG, infos[i].getTypeName() + " is " + infos[i].isConnected());
                } else if ( infos[i].getTypeName().equalsIgnoreCase("WIFI") ){ 
                    if((infos[i].isConnected() != hasWifi)){
                        hasChanged = true;
                        hasWifi = infos[i].isConnected();
                    }
                    Log.d(TAG, infos[i].getTypeName() + " is " + infos[i].isConnected());
                }
            }
 
            hasConnectivity = hasMmobile || hasWifi;
            Log.v(TAG, "hasConn: " + hasConnectivity + " hasChange: " + hasChanged + " - "+(mqttClient == null || !mqttClient.isConnected()));
            if (hasConnectivity && hasChanged && (mqttClient == null || !mqttClient.isConnected())) {
                doConnect();
            } else if (!hasConnectivity && mqttClient != null && mqttClient.isConnected()) {
                Log.d(TAG, "doDisconnect()");
                try {
                    token = mqttClient.disconnect();
                    token.waitForCompletion(1000);
                } catch (MqttException e) {
                    e.printStackTrace();
                }
            }
        }
    };
 
    public class MQTTBinder extends Binder {
        public MQTTService getService(){
        	return MQTTService.this;
        }
    }
 
    @Override
    public void onCreate() {
        IntentFilter intentf = new IntentFilter();
        setClientID();
        intentf.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(new MQTTBroadcastReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
    }
 
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.d(TAG, "onConfigurationChanged()");
        android.os.Debug.waitForDebugger();
        super.onConfigurationChanged(newConfig);
 
    }
 
    private void setClientID(){
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo wInfo = wifiManager.getConnectionInfo();
        deviceId = wInfo.getMacAddress();
        if(deviceId == null){
            deviceId = MqttAsyncClient.generateClientId();
        }
    }
 
    private void doConnect(){
        Log.d(TAG, "doConnect()");
        IMqttToken token;
        MqttConnectOptions options = new MqttConnectOptions();
        options.setCleanSession(true);
        try {
            mqttClient = new MqttAsyncClient("tcp://mqtt.example.com:1883", deviceId, new MemoryPersistence());
            token = mqttClient.connect();
            token.waitForCompletion(3500);
            mqttClient.setCallback(new MqttEventCallback());
            token = mqttClient.subscribe("testtopic", 0);
            token.waitForCompletion(5000);
        } catch (MqttSecurityException e) {
            e.printStackTrace();
        } catch (MqttException e) {
            switch (e.getReasonCode()) {
            case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
            case MqttException.REASON_CODE_CLIENT_TIMEOUT:
            case MqttException.REASON_CODE_CONNECTION_LOST:
            case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
                Log.v(TAG, "c" +e.getMessage());
                e.printStackTrace();
                break;
            case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
                Intent i = new Intent("RAISEALLARM");
                i.putExtra("ALLARM", e);
                Log.e(TAG, "b"+ e.getMessage());
                break;
            default:
                Log.e(TAG, "a" + e.getMessage());
            }
        }
    }
 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG, "onStartCommand()");
        return START_STICKY;
    }
 
    private class MqttEventCallback implements MqttCallback {
 
        @Override
        public void connectionLost(Throwable arg0) {
 
 
        }
 
        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {
 
        }
 
        @Override
        @SuppressLint("NewApi")
        public void messageArrived(String topic, final MqttMessage msg) throws Exception {
        	Log.i(TAG, "Message arrived from topic" + topic);
        	Handler h = new Handler(getMainLooper());
        	h.post(new Runnable() {
        		@Override
        		public void run() {
        		    Intent launchA = new Intent(MQTTService.this, FullscreenActivityTest.class);
        		    launchA.putExtra("message", msg.getPayload());
        		    //TODO write somethinkg that has some sense
        		    if(Build.VERSION.SDK_INT >= 11){
        		        launchA.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_REORDER_TO_FRONT|Intent.FLAG_ACTIVITY_NO_ANIMATION);
        		    } /*else {
        		        launchA.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        		    }*/
        		    startActivity(launchA);
        			Toast.makeText(getApplicationContext(), "MQTT Message:\n" + new String(msg.getPayload()), Toast.LENGTH_SHORT).show();
        		}
        	});
        }
    }
 
    public String getThread(){
        return Long.valueOf(thread.getId()).toString();
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind called");
        return null;
    }
 
}
Share

19 Replies to “Android MQTT service – Code example”

  1. I tried couple of examples for Android. Most of them did not work for me. Samples were working are too complicated. I got scared when I saw them. This is really really fantastic. Simple and works like a charm. Thank you very much!!!! Saved my days…

  2. Thank you very much

    Almost four weeks, I tried to find a way to keep MQTT service running even if the app closed so the widget can be updated, the paho sample seemed to not work when the activity shut down.

    but yours is very simple, clear and exactly perfect thank you!

  3. I get the below error when i try to run this code from my application. I added this service into android manifest file and started my application. It throws the below error. Can you help?

    D/MQTTService﹕ WIFI is true
    V/MQTTService﹕ hasConn: true hasChange: true – true
    D/MQTTService﹕ doConnect()
    V/MQTTService﹕ cTimed out waiting for a response from the server
    W/System.err﹕ at org.eclipse.paho.client.mqttv3.internal.Token.waitForCompletion(Token.java:112)
    W/System.err﹕ at org.eclipse.paho.client.mqttv3.MqttToken.waitForCompletion(MqttToken.java:67)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService.doConnect(MQTTService.java:124)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService.access$400(MQTTService.java:34)
    W/System.err﹕ at com.trimble.fsm.fieldmaster.service.MQTTService$MQTTBroadcastReceiver.onReceive(MQTTService.java:71)

  4. @dk I’m newbie but it seems your error related to the server (time out waiting for response), try other server: iot.eclipse.org OR test.mosquitto.org and see..
    Make sure that your server is working, if so you may need to increase the time out.

  5. Nice code but you didn’t specify the permissions for the Android manifest.. Sorry am still new to this..

  6. Same story as the rest :P New to Android development and struggling to get an MQTT app of the ground. this example is the closest I’ve come to understanding how the Paho library works, But still cant seem to get it to work properly. Followed this example and trying to connect to mosquittos test broker and keep getting this:

    D/MQTTService: MOBILE is true
    D/MQTTService: WIFI is false
    V/MQTTService: hasConn: true hasChange: true – true
    D/MQTTService: doConnect()
    E/MQTTService: aMqttException

    I monitored my network traffic and it isn’t even trying to send any data to the server. Not to sure what I’m doing wrong

  7. Great code snippet, got it to work without problems.
    Do you have a code snippet for publishing a message with MQTT as well?

  8. Never mind, found a solution to put into my main appby using your code and change it to publishing:
    public void doPublish(String topic, String payload){
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “doPublish()”);
    if (MQTTService.mqttClient == null) { // If service is not (yet) active, don’t publish
    return;
    }
    IMqttToken token;
    try {
    byte[] encodedPayload;
    encodedPayload = payload.getBytes(“UTF-8”);
    MqttMessage message = new MqttMessage(encodedPayload);
    token = MQTTService.mqttClient.publish(topic, message);
    token.waitForCompletion(5000);
    } catch (MqttSecurityException | UnsupportedEncodingException e) {
    e.printStackTrace();
    } catch (MqttException e) {
    switch (e.getReasonCode()) {
    case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
    case MqttException.REASON_CODE_CLIENT_TIMEOUT:
    case MqttException.REASON_CODE_CONNECTION_LOST:
    case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “c” +e.getMessage());
    e.printStackTrace();
    break;
    case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
    Intent i = new Intent(“RAISEALLARM”);
    i.putExtra(“ALLARM”, e);
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “b”+ e.getMessage());
    break;
    default:
    if (BuildConfig.DEBUG) Log.d(DEBUG_LOG_TAG, “a” + e.getMessage());
    }
    }
    }

  9. How to connect google cloud platform with iot and mqtt protocol. When i pass ssl://mqtt.googleapis.com:8883 this is not work please help me i don’t know how to connect android app with google cloud platform with iot.

  10. This job is really what I was looking for!
    However I have a small question: how can I subscribe to different topics by adding them at run time?

    1. Hey, Iam a noob on Android Studio and I can’t (import com.simonecaruso.mqtt.FullscreenActivityTest) you know how to do it ?

  11. Fantastic bit of work there. Thank you, saved me a bunch of time.

    I thing I did notice, you need to pass the options variable in to the connect() function.
    I wanted to use options.setCleanSession(false) but it took me a moment to see that it was never used

Leave a Reply to samset Cancel reply

Your e-mail address will not be published. Required fields are marked *