MQTT: An Open Source Push Messaging Alternative

Version 3

    Introduction

     

    Push technology has become an integral part of the mobile application experience in both consumer, and enterprise applications.  Developers writing for Android devices that ship with Google Mobile Services (GMS) have the option to use Google Cloud Messaging (GCM) to incorporate push messaging in their applications.  Developers writing for devices that do not have GMS, must find an alternative to GCM, if they want to incorporate push messaging in their applications.  A developer has the usual choices if they want push messaging on non GMS devices, find a vendor that offers a push messaging service or create their own.  The typical list of advantages and disadvantages, cost, support, maintenance, reliability, longevity (will the vendor be around in the future), must be considered when choosing one of the available options.  An additional consideration for the enterprise is connectivity, the commercial options, including GCM are cloud-based, access to the internet is required.  Cloud-based, and internet connectivity are related, but possibly distinct concerns; a business may not trust their data in the cloud, a business may not want to provide internet access to their devices.  A third option for push messaging is MQTT, an open source publish/subscribe protocol that can be used as the foundation of a push messaging service.  An MQTT based solution might address concerns that arise with home-brewed and free solutions.  The MQTT protocol was created at IBM, the related code was donated by IBM to the Eclipse Paho project where it is being actively maintained and developed.  An open source MQTT server can be installed locally, internet connectivity is not required for in the four walls applications, a business does not have to put any information in the cloud if it does not want to, and the MQTT protocol supports SSL encrypted connections. Please see the resources section for links to information about, MQTT, Paho, and the open source server Moquitto.

     

    This article examines an Android push messaging application using the Java MQTT client library from the Paho project.  The client library (org.eclipse.paho.client.mqttv3.jar)  is substantial, providing a comprehensive API.  The author of this article does not profess to be an expert using the Paho library; neither the source code nor the available features have been studied in-depth, rather, a simple application using a minimum set of features was created to show how it could be done.  An introduction to some basic usage of the Paho library is followed by a detailed breakdown of an application using the library.

     

    Paho Client Library

     

    The Paho client library consists of a set of classes and interfaces that comprise the API, and a Service that handles the TCP/IP sockets used to connect to a message broker.  A user of the API is not required to have any socket programming knowledge or experience.  To use the Service an application must have the following entry in the manifest.

     

            <!-- Mqtt Service -->
            <service android:name="org.eclipse.paho.android.service.MqttService" >
            </service>
    
    
    
    
    
    
    
    

     

    Since this Service uses the network the following permission is also required in the manifest.

     

        <uses-permission android:name="android.permission.INTERNET" />
    
    
    
    
    
    
    
    

     

    Using the library, an application can connect to, and communicate with a broker either synchronously, or asynchronously.  In the sample application a choice was made to keep MQTT interactions in a separate Thread, so the synchronous client was chosen.  Most of the code in the library is very well documented using Javadoc, the code and related documentation should be referred to for the most in-depth understanding of the library.

     

    Overview and Usage

     

    Client communication with a server consists of just a few basic principles, connecting, making requests and receiving messages.  As one would hope, using the Paho library to communicate with a message broker is simple and intuitive.  The MqttClient is used to connect to and communicate with a message broker.  An application first instantiates an MqttClient and then calls the appropriate methods to make requests.

     

                    MqttClient client = null;
                    try
                    {
                        client = new MqttClient("tcp://iot.eclipse.org:1883", MqttClient.generateClientId(), null);
                    }
                    catch (MqttException e1)
                    {
                        e1.printStackTrace();
                    }
                }
    
    
    
    
    
    
    

     

    Many of the methods found in the library throw exceptions when something goes wrong, here, getting the client object is enclosed in a try/catch block.  The first parameter passed to the constructor contains the location of the broker to be contacted, in this case it is the address and port of a real public broker.  Port 1883 is the standard port used by a broker, it is registered with IANA.  The second parameter is a client identifier, in this case a static method provided by the class is used to generate a unique identifier.  The third parameter is optional, it is used for a persistent data store to implement QOS.  For more information about the data store and QOS please refer to the the MqttClientPersistence class definition and the MQTT protocol.

     

    Once an MqttClient Object is obtained, a connection can be made to the server, by calling the connect method.

     

                            MqttConnectOptions options = new MqttConnectOptions();
                            try
                            {
                                client.connect(options);
                            }
                            catch (MqttException e)
                            {                  
                                Log.d(getClass().getCanonicalName(), "Connection attempt failed with reason code = " + e.getReasonCode() + ":" + e.getCause());
                            }
    
    
    
    
    
    
    

     

    The MqttConnectOptions Object passed to the connect method is used to adjust connection parameters, such as keep alive interval, and connection timeouts, or for inclusion of any additional information that is required to make an SSL broker connection.  Since a synchronous client is being used, the call will block and return on success, or throw an exception on failure.  In this case the failure is logged, an example log entry is shown below.  This particular log message occurred after the wireless radio was turned off.

     

    D/com.example.MQTT.MQTTservice.MQTTConnection.MsgHandler(19533): Connection attempt failed with reason code = 0:java.net.UnknownHostException: Host is unresolved: iot.eclipse.org

     

    As mentioned, a synchronous client is being used in this example (MqttClient as opposed to  MqttAsyncClient).  This means that requests, like connect, will block and return or throw an exception.  There is no polling or read method to get messages from the server, messages from the server can arrive at any time.  The library provides a callback mechanism to handle this behavior, methods in an MqttCallback Object registered with a client, will be invoked as appropriate.  MqttCallback is an interface that must be implemented by another class, a  trivial and not too useful class is defined below.

     

    public class exampleCallBack implements MqttCallback
    {
        public void connectionLost(Throwable cause)
        {
              Log.d(getClass().getCanonicalName(), "MQTT Server connection lost" + e.getReasonCode());
        }
        public void messageArrived(String topic, MqttMessage message)
        {
              Log.d(getClass().getCanonicalName(), "Message arrived:" + topic + ":" + message.toString());
        }
        public void deliveryComplete(IMqttDeliveryToken token)
        {
              Log.d(getClass().getCanonicalName(), "Delivery complete");
        }
    }
    
    
    
    
    
    

     

    To enable the callback feature, a callback object is registered with a client, this would most logically be done prior to connecting to the server, as shown on line five below.

     

                    MqttClient client = null;
                    try
                    {
                        client = new MqttClient(uri, MqttClient.generateClientId(), null);
                        client.setCallback(new exampleCallback());
                    }
                    catch (MqttException e1)
                    {
                        e1.printStackTrace();
                    }
    
    
    
    
    
    

     

     

    Once a client is successfully connected to a server, it can make requests to receive messages, that is, subscribe to topics, and publish messages.  The code below shows how a client subscribes to the topic "news".  Once subscribed, messages published to this topic will be delivered to this client, the registered callback method messageArrived will be automatically invoked by the MqttService.

              

                    try
                    {
                        client.subscribe("news");
                    }
                    catch (MqttException e)
                    {
                        Log.d(getClass().getCanonicalName(), "Subscribe failed with reason code = " + e.getReasonCode());
                        return false;
                    }
    
    
    
    
    
    

     

    The code below shows how to publish a message to the topic "news", and concludes the overview and usage of the Paho library.  The remainder of this document describes in detail an application that uses the library.  Experienced developers that are not interested in the details of the design and implementation of the example application are invited to stop here and explore the attached project independently.

     

                   /**
                    * An MqttMessage holds the application payload and options
                    * specifying how the message is to be delivered
                    * The message includes a "payload" (the body of the message)
                    * represented as a byte[].
                    */
    
                    String msg = "Something really good happened";
                    try
                    {
                        MqttMessage message = new MqttMessage();
                        message.setPayload(msg.getBytes());
                        client.publish("news", message);
                    }
                    catch (MqttException e)
                    {
                        Log.d(getClass().getCanonicalName(), "Publish failed with reason code = " + e.getReasonCode());
                    }  
    
    
    
    
    

     

     

     

     

     

    Example Application High Level Design

     

    The MQTT protocol uses a client/server architecture, clients connect to the server (message broker), and make requests.  Message broker clients interested in receiving messages, subscribe to a topic, clients interested in having messages “pushed”, submit publish requests to a broker.  The example application has two major components, a Service, and an Activity.  The Service acts as a proxy for activities that want to interact with a message broker.  The Service also dispatches messages from a message broker in the form of Notifications and Intents.

     

    Service

     

    The Service has three functions, communicating with a message broker, providing a programming interface to clients, and push message distribution.

     

    Communication with the message broker is accomplished using the Paho client jar file.  Clients using the Paho library can choose asynchronous or synchronous communication.  It is also possible for clients to define a local data store for message caching, used when a connection to a broker is unavailable.  For simplicity, this example application uses a  synchronous client connection, with no data cache.  When the Service starts it immediately tries to connect to a broker, retrying until successful.

     

    The Service supports a set of three commands, PUBLISH, SUBSCRIBE and REGISTER.  PUBLISH and SUBSCRIBE perform the obvious functions, REGISTER is used to define how messages received from the broker are distributed.  In order to receive push messages,  at least one SUBSCRIBE request must be made.

     

    Message distribution can occur in two ways, using Android Notifications or using both Notifications and Intents.  A Service client, using the REGISTER command, can specify two pieces of information, an Activity to launch when a user taps a notification, and an Intent to be broadcast when a message is received from the broker.

     

     

    Activity

     

    The main Activity has three functions, providing a user interface (UI), establishing communication with the Service, and configuring message distribution behavior.

     

    The UI contains a text entry field with an associated button to subscribe to a topic,  a text entry field with an associated button to publish messages to a topic, and a status field that is used to report that result of requests submitted to the Service.

     

    Detailed Design and Implementation

     

    This application was developed in Eclipse.  It was started using the wizard to create a new Android Application Project.  A new file was added to the project to define the Service,  MQTTservice.java.

     

    Service

     

    The three functions of the Service are defined in three classes, MQTTConnection, ClientHandler and MQTTService.

     

    MQTTConnection

     

    MQTTConnection manages the connection to, and communication with, a message broker.  Most the real work of the is performed by the inner class MsgHandler.  MQTTConnection exposes three methods for making requests to the broker, and configuring message distribution behavior.  MQTTConnection  extends the Android class Thread and defines the inner class MsgHandler that extends the Android class Handler.  Handler provides a convenient way to communicate with a Thread using the sendMessage method.  Although the broker connection is made using the synchronous client, events such as message reception and connection loss still occur asynchronously.  Paho defines the Interface MqttCallback with the methods required to handle asynchronous events.  MsgHandler implements MqttCallback and the methods connectionLost and messageArrived.

    ClientHandler

     

    ClientHandler provides the client programming interface for the Service.  ClientHandler extends the Android class Handler.  Clients make requests by sending an Android Message to ClientHandler.  A Message contains a field named what that describes the Message, an Android Bundle containing additional data can be added to a message.  When a Message is sent to a Handler, the handleMessage method is automatically invoked.   A class that extends Handler typically overrides this method, when handleMessage is called, the what field can be examined to determine what the sender of the message wants.

    MQTTService

     

    MQTTService extends the Android Service.  MQTTService is a bound Service, that is, clients that wish to communicate with the Service must call the bindService method.  MQTTService defines a final static member clientMessenger of type Messenger, it is simply a reference to a Handler, in this case ClientHandler.  When bindService is called with MQTTService.class as a parameter, the onBind method of MQTTService is called.  The value returned by onBind is clientMessenger.getBinder() which is essentially a reference to ClientHandler, establishing a communication channel between  callers of bindService and MQTTService.

    BootReceiver

     

    This application project contains one additional module, BootReceiver.java that contains the definition of BootReceiver.  BootReceiver extends the Android class BroadcastReciever.  BootReceiver overrides  the onReceive method and registers for the BOOT_COMPLETED Intent by means of the project manifest.

     

     

    Service Initialization

     

    The diagram below presents an approximate sequence of events and messages, with pseudo-code, illustrating the initialization of the Service.  Following the diagram is the corresponding detailed code view of what is happening.

     

    flow.jpg

     

    The onReceive method of BootReceiver is called when the BOOT_COMPLETED Intent is delivered by the operating system.  In onReceive  BootReceiver starts the MQTTService.

     

    public class BootReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.d(getClass().getCanonicalName(), "onReceive");
            context.startService(new Intent(context, MQTTservice.class));
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    

     

    The onCreate method of MQTTservice is called creating a new MQTTConnection.

     

        @Override
        public void onCreate()
        {
            super.onCreate();
            connection = new MQTTConnection();
        }
    
    
    
    
    
    
    
    
    
    
    
    
    
    

     

    The MQTTConnection contructor creates a MsgHandler and sends it a CONNECT request.  As mentioned earlier, most of the real work takes place in MsgHandler.  More detail about MsgHandler will be given later.

     

            MQTTConnection()
            {
                msgHandler = new MsgHandler();
                msgHandler.sendMessage(Message.obtain(null, CONNECT));
            }
    
    
    
    
    
    
    
    
    
    
    
    
    
    

     

     

    When startService is called with MQTTservice.class as a parameter, the OnStartCommand method of MQTTService is called, initiating a connection to a message broker.  The isRunning method is utility method to ensure only one copy the Service is started, START_STICKY indicates that the OS should try to restart the Service if it dies.  The call connection.start(), starts the Thread that listens for incoming messages.

     

        @Override
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            if (isRunning())
            {
                return START_STICKY;
            }
    
            super.onStartCommand(intent, flags, startId);      
            connection.start();
    
            return START_STICKY;
        }
    
    
    
    
    
    
    
    
    
    
    
    
    
    

     

     

    MsgHandler manages the connection to a broker, makes requests to the broker on behalf of clients, and receives messages from the broker.  The constructor initializes local variables, obtains a new MqttClient object and registers itself for callbacks.  The parameters passed to the MqttClient contructor specfify the location of the broker (host and port), and a unique identifier.  The broker location is hard-coded to use a public MQTT server.  Notice that the broker listens for connections on a TCP/IP port.  Traffic over this connection is in clear text, MQTT does however, support SSL connections.

     

                private final String HOST = "iot.eclipse.org";
                private final int PORT = 1883;
                private final String uri = "tcp://" + HOST + ":" + PORT;
    
                MsgHandler()
                {
                    options.setCleanSession(true);
                    try
                    {
                        client = new MqttClient(uri, MqttClient.generateClientId(), null);
                        client.setCallback(this);
                    }
                    catch (MqttException e1)
                    {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
    
    
    
    
    
    
    
    
    
    
    
    

     

     

    The MQTTConnection constructor sends a CONNECT message to the MsgHandler object right after creating it.  The handleMessage method is automatically invoked to handle this message.  The relevant section of code is shown below.  The method first determines the type of message by examining the what field of the message. The connect method of the MqttClient object is called, a synchronous call, it either returns if a connection is successful, or throws an exception.  If the connection fails, the handler sends itself a message to try CONNECT again in "timeout" milliseconds.

     

                @Override
                public void handleMessage(Message msg)
                {
                    switch (msg.what)
                    {
                    case CONNECT:
                    {
                        if (connState != CONNECT_STATE.CONNECTED)
                        {
                            try
                            {
                                client.connect(options);
                                connState = CONNECT_STATE.CONNECTED;
                                Log.d(getClass().getCanonicalName(), "Connected");
                                timeout = MINTIMEOUT;
                            }
                            catch (MqttException e)
                            {        
                                Log.d(getClass().getCanonicalName(), "Connection attemp failed with reason code = " + e.getReasonCode() + e.getCause());
                                if (timeout < MAXTIMEOUT)
                                {
                                    timeout *= 2;
                                }
                                this.sendMessageDelayed(Message.obtain(null, CONNECT), timeout);
                                return;
                            }
    
    
    
    
    
    
    
    
    
    
    
    

     

    Client Requests

     

    After onStartCommand in MQTTService has finished, the Service is ready to accept client connections and handle requests.  An application that wants to communicate with this Service must call the bindService method with the name of this Service as a parameter.   When clients call bindService, the onBind method of the Service is called and a reference to the ClientHandler object is returned.  The callers of bindService obtain this reference and use it to send messages to the Service.

     

        @Override
        public IBinder onBind(Intent intent)
        {
            /*
             * Return a reference to our client handler.
             */
            return clientMessenger.getBinder();
        }
    
    
    
    
    
    
    
    
    
    
    
    

     

    When a bound client sends a message to the service the handleMessage method of ClientHandler is called.  As described earlier the Service supports three request types, and MQTTClient provides three public methods to send requests to the broker and configure message distribution, more about this will follow.  Exactly like the Handler in MQTTConnection, handleMessage examines the what field to determine the function being requested by the caller.  For SUBSCRIBE and PUBLISH, the public method makeRequest is called.  If possible, a response to the client will be made asynchronously from the Handler in MQTTConnection.  For REGISTER, the caller can specify which Activity to launch when a Notification is tapped, and which Intent to broadcast when a message is received by the broker.  The configuration methods setPushCallback and setIntentname do not require communication with the broker, they are handled locally, a response can be sent right back to the caller using ReplytoClient.

     

     

         class ClientHandler extends Handler
         {
             @Override
             public void handleMessage(Message msg)
             {
                 boolean status = false;
    
                 switch (msg.what)
                 {
                 case SUBSCRIBE:
                 case PUBLISH:
                            /*
                             * These two requests should be handled by
                             * the connection thread, call makeRequest
                             */
                            connection.makeRequest(msg);
                            break;
                    case REGISTER:
                 {
                     Bundle b = msg.getData();
                     if (b != null)
                     {
                         Object target = b.getSerializable(CLASSNAME);
                         if (target != null)
                         {
                             /*
                              * This request can be handled in-line
                              * call the API
                              */
                             connection.setPushCallback((Class<?>) target);
                             status = true;
                         }
                         CharSequence cs = b.getCharSequence(INTENTNAME);
                         if (cs != null)
                         {
                             String name = cs.toString().trim();
                             if (name.isEmpty() == false)
                             {
                                 /*
                                  * This request can be handled in-line
                                  * call the API
                                  */
                                 connection.setIntentName(name);
                                 status = true;
                             }
                         }
                     }
                     ReplytoClient(msg.replyTo, msg.what, status);
                     break;
                 }
                 }
             }
         }
    
    
    
    
    
    
    
    
    
    
    

     

    The last part of the Service to be discussed, and the one that performs most of the real work is in MQTTConnection.  MQTTConnection is wrapper around the MQTT client library, it is the interface from the Service to the broker.  First, the three public methods that provide the interface to the client message handler.  The two "set" methods simply assign values to local variables that will be used when a message arrive from the broker.  The method makeRequest takes the Message that was received by the ClientHandler and sends a copy of it to the Handler defined in  MQTTConnection.  The idea is to have the Thread associated with the MQTT server handle the MQTT server requests.

     

            public void makeRequest(Message msg)
            {
                /*
                 * It is expected that the caller only invokes
                 * this method with valid msg.what.
                 */
                msgHandler.sendMessage(Message.obtain(msg));
            }
    
            public void setPushCallback(Class<?> activityClass)
            {
                launchActivity = activityClass;
            }
    
            public void setIntentName(String name)
            {
                intentName = name;
            }
    
    
    
    
    
    
    
    
    
    

     

     

    The handleMessage method was described briefly when a CONNECT request is made as part of initialization, and there is not too much more to discuss that isn't obvious at this point.  When a MsgHandler object is instantiated if passes itself to the Mqttclient as a callback.  This class implements the method messageArrived defined in the MqttCallback interface.  This method messageArrived is called by the MQTT library when the message broker sends out a message to all clients that have subscribed to a topic.  If a Service client made a REGISTER request and specified an Intent, that Intent will be broadcast.

    If a Service client made a REGISTER request and specified an Activity to launch from a Notification, that information will be added to the PendingIntent that is added to the Notification.

     

     

               @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception
                {
                    Log.d(getClass().getCanonicalName(), topic + ":" + message.toString());
        
                    if (intentName != null)
                    {
                        Intent intent = new Intent();
                        intent.setAction(intentName);
                        intent.putExtra(TOPIC, topic);
                        intent.putExtra(MESSAGE, message.toString());
                        sendBroadcast(intent);
                    }
        
    
                    Context context = getBaseContext();
                    PendingIntent pendingIntent = null;
            
                    if (launchActivity != null)
                    {
                        Intent intent = new Intent(context, launchActivity);
                        intent.setAction(Intent.ACTION_MAIN);
                        intent.addCategory(Intent.CATEGORY_LAUNCHER);
            
                        //build the pending intent that will start the appropriate activity
                        pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
                    }
            
                    //build the notification
                    Builder notificationCompat = new Builder(context);
                    notificationCompat.setAutoCancel(true)
                            .setContentIntent(pendingIntent)
                            .setContentText( message.toString())
                            .setSmallIcon(R.drawable.ic_launcher);
    
                    Notification notification = notificationCompat.build();
                    NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                    nm.notify(mid++, notification);
    
                }
            }
        }
    
    
    
    
    
    
    
    
    
    

     

     

     

     

    Activity

     

    The three functions of the main Activity, Service communication, user interface and configuring message distribution, are discussed in detail in the following sections.

     

    Activity Initialization

     

    The diagram below presents an approximate sequence of events and messages, with pseudo-code, illustrating the initialization of the Activity with regard to communication with the Service.  Following the diagram is the corresponding detailed code view of what is happening.

     

    ActivityInitialization.png

     

    Service Communication

     

    The Activity communicates with the Service by calling bindService with the Service name.  The bindService method also requires a parameter that is an Object of type ServiceConnection.  A ServiceConnection Object is used as a callback to notify the caller of bindService of changes in the connection to the Service.

     

        @Override
        protected void onStart()
        {
            super.onStart();
            bindService(new Intent(this, MQTTservice.class), serviceConnection, 0);
        }
    
    
    
    
    
    
    
    
    
    
    

     

    The parameter serviceConnection used in the call to bindService is defined as an inner class of the main Activity is given below.  The call to bindService results in the Service method onBind being called.  The Service returns a reference to its Handler.  The callback method onServiceConnected in serviceConnection is called.  From the IBinder parameter, a reference to the Service Handler is obtained.  The Messenger class defines the methods for sending messages to the Service Handler.  The Messager Object service, is defined at the Activity level so that is can be used by other methods defined in the class.  Using an Android Message, onServiceConnected prepares REGISTER request, one of the three request types defined by the Service.  The REGISTER request supports two optional parameters, CLASSNAME, and INTENTNAME, that are put into an Android Bundle and associated with the Message.  The CLASSNAME defines an Activity to be launched when a Notification generated by the Service is tapped, in this case it is the MainActivity of this application.  The INTENTNAME, specifies an Intent that should be broadcast by the Service when a message arrives from the message broker.  Similar to the Service, the MainActivity defines a Handler called ServiceHandler, a Messenger Object containing a reference to the Handler is added to the message sent to the Service, so that the Service can reply.

     

     

       private ServiceConnection serviceConnection = new ServiceConnection()
        {
            @Override
            public void onServiceConnected(ComponentName arg0, IBinder binder)
            {
                service = new Messenger(binder);
                Bundle data = new Bundle();
                data.putSerializable(MQTTservice.CLASSNAME, MainActivity.class);
                data.putCharSequence(MQTTservice.INTENTNAME, "com.example.MQTT.PushReceived");
                Message msg = Message.obtain(null, MQTTservice.REGISTER);
                msg.setData(data);
                msg.replyTo = serviceHandler;
                try
                {
                    service.send(msg);
                }
                catch (RemoteException e)
                {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName arg0)
            {
            }
        };
    
    
    
    
    
    
    
    
    
    
    

     

    User Interface

     

    An image of the user interface is shown below.  A user subscribes to a topic by entering text in the text field and tapping the Subscribe button.  Similarly to publish a message text is entered into the topic text field, a message is entered in the Message field and the Publish button is tapped.  Below the entry fields the status of requested is reported.

    client.png

     

    The code associated with the publish button is given below, the subscribe button works in a similar way.  After verifying parameters, a PUBLISH request is created.  Using a Bundle the topic and message strings are added to the Message.  The Messenger Object, service, saved by onServiceConnected is used to send the message to the Service.  As in the REGISTER request the Activity Handler, shown on line twenty-four.

     

            Button publishButton = (Button) findViewById(R.id.buttonPublish);
            publishButton.setOnClickListener(new OnClickListener()
            {
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                @Override
                public void onClick(View arg0)
                {             
                    EditText t = (EditText) findViewById(R.id.EditTextTopic);
                    EditText m = (EditText) findViewById(R.id.editTextMessage);
                    TextView result = (TextView) findViewById(R.id.textResultStatus);
                    inputMethodManager.hideSoftInputFromWindow(result.getWindowToken(), 0);
                  
                    String topic = t.getText().toString().trim();
                    String message = m.getText().toString().trim();
                  
                    if (topic != null && topic.isEmpty() == false && message != null && message.isEmpty() == false)
                    {
                        result.setText("");
                        Bundle data = new Bundle();
                        data.putCharSequence(MQTTservice.TOPIC, topic);
                        data.putCharSequence(MQTTservice.MESSAGE, message);
                        Message msg = Message.obtain(null, MQTTservice.PUBLISH);
                        msg.setData(data);
                        msg.replyTo = serviceHandler;
                        try
                        {
                            service.send(msg);
                        }
                        catch (RemoteException e)
                        {
                            e.printStackTrace();
                            result.setText("Publish failed with exception:" + e.getMessage());
                        }
                    }
                    else
                    {
                        result.setText("Topic and message required.");
                    }
                }
            });
    
    
    

     

    The Service responds to requests by calling the send method of the Messenger Object in the replyTo field of a received Message.  Messages sent to the client are handled by the handleMessage method of the Handler defined in the Activity.  The type of message is examined to determine if it is one of the types supported by the Service, if it is, status is extracted from the Message and displayed on screen.

     

        class ServiceHandler extends Handler
        {
            @Override
            public void handleMessage(Message msg)
            {
                    switch (msg.what)
                    {
                    case MQTTservice.SUBSCRIBE:     break;
                 case MQTTservice.PUBLISH:        break;
                 case MQTTservice.REGISTER:        break;
                 default:
                     super.handleMessage(msg);
                     return;
                    }
              
                   Bundle b = msg.getData();
                   if (b != null)
                   {
                       TextView result = (TextView) findViewById(R.id.textResultStatus);
                       Boolean status = b.getBoolean(MQTTservice.STATUS);
                       if (status == false)
                       {
                          result.setText("Fail");
                       }
                       else
                       {
                          result.setText("Success");
                       }
                   }
            }
        }
    
    
    

     

     

    Once last detail of the Activity is a BroadcastReceiver that is defined to receive the Intent specified when the Activity sent a REGISTER request to the Service.  Information added by the Service to the Intent is displayed as Toast.

     

     

        public class PushReceiver extends BroadcastReceiver
        {
            @Override
            public void onReceive(Context context, Intent i)
            {
                String topic = i.getStringExtra(MQTTservice.TOPIC);
                String message = i.getStringExtra(MQTTservice.MESSAGE);
                Toast.makeText(context, "Push message received - " + topic + ":" + message, Toast.LENGTH_LONG).show();
            }
        }
    
    
    

     

    The BroadCastReceiver is added and removed dynamically as part of the Activity life cycle, it does not appear in the manifest.

     

         @Override
        protected void onResume()
        {
             super.onResume();
            registerReceiver(pushReceiver, intentFilter);
        }
      
        @Override
        protected void onPause()
        {
            super.onPause();
            unregisterReceiver(pushReceiver);
        }
    
    
    

     

     

     

    Resources

     

    MQTT – http://mqtt.org

    Paho - http://www.eclipse.org/paho

    Mosquitto – http://mosquitto.org

    Paho Release Information – https://projects.eclipse.org/projects/technology.paho/documentation