Table of Contents
Just a second...

Start subscribing with Android

Create an Android™ client application within minutes that connects to the Diffusion™ server. This example creates a client that prints the value of a topic to the console when the topic is updated.

To complete this example, you need Android Studio installed on your development system and a Diffusion server.

You also require that anonymous client connections are assigned a role with the select_topic and read_topic permissions. For example, the "CLIENT" role. For more information about roles and permissions, see Role-based authorization.

This example steps through the lines of code required to subscribe to a topic. The full code example is provided after the steps.
  1. Set up a project in Android Studio that uses the Diffusion Unified API.
    1. Create a new project using API Level 21 or later.
    2. Copy the diffusion-android-x.x.x.jar into the libs folder of your project.
    3. Open the Dependency window in the project's module settings and add diffusion-android-x.x.x.jar as a file dependency.
  2. In your project's AndroidManifest.xml file set the INTERNET permission.
    <uses-permission android:name="android.permission.INTERNET"/>
    This permission is required to use the Diffusion API.
  3. Open your project's MainActivity.java file.
    This file is where you develop the code to interact with the Diffusion server.
    The empty MainActivity.java file contains the following boilerplate code:
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
    
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    }
  4. Import the following packages and classes:
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    
    import com.pushtechnology.diffusion.client.Diffusion;
    import com.pushtechnology.diffusion.client.callbacks.ErrorReason;
    import com.pushtechnology.diffusion.client.content.Content;
    import com.pushtechnology.diffusion.client.features.Topics;
    import com.pushtechnology.diffusion.client.features.Topics.TopicStream;
    import com.pushtechnology.diffusion.client.session.Session;
    import com.pushtechnology.diffusion.client.session.SessionFactory;
    import com.pushtechnology.diffusion.client.types.UpdateContext;
    
    public class MainActivity extends AppCompatActivity {
    
    }
  5. Create a TopicStreamLogcat static inner class that extends TopicStream.Default.

    Inside the inner class, override the onTopicUpdate to print any topic updates received by your Android client to the log console.

        private static class TopicStreamLogcat extends TopicStream.Default {
            @Override
            public void onTopicUpdate(String topic, Content content,
                                      UpdateContext context) {
    
                Log.i("Topic Stream", topic + ":   " + content.asString());
            }
        }
          
  6. Create a SessionHandler inner class that implements SessionFactory.OpenCallback.
    This inner class will contain the code that interacts with the Diffusion server.
        private class SessionHandler implements SessionFactory.OpenCallback {
            private Session session = null;
    
            @Override
            public void onOpened(Session session) {
    
            }
    
            @Override
            public void onError(ErrorReason errorReason) {
                
            }
    
            public void close() {
                if ( session != null ) {
                    session.close();
                }
            }
        }
  7. In the onOpened method, create the code required to subscribe to the foo/counter topic.
    1. Get the Topics feature.
          // Get the Topics feature to subscribe to topics
          final Topics topics = session.feature( Topics.class );
    2. Add an instance of TopicStreamLogcat as the topic stream for the foo/counter topic.
          // Add a new topic stream for 'foo/counter'
          topics.addTopicStream(">foo/counter", new TopicStreamLogcat());
    3. Subscribe to the foo/counter topic.
          // Subscribe to the topic 'foo/counter'
          topics.subscribe("foo/counter", new Topics.CompletionCallback.Default());
  8. In the MainActivity class, declare an instance of session handler.
    private SessionHandler sessionHandler = null;
  9. Override the onCreate method of the MainActivity class to open the session with the Diffusion server.
    Note: Ensure that you use the asynchronous open() method with a callback. Using the synchronous open() method might open a connection on the same thread as the UI and cause a runtime exception. However, the synchronous open() method can be used in any thread that is not the UI thread.
            if ( sessionHandler == null ) {
                sessionHandler = new SessionHandler();
    
                // Connect anonymously
                // Replace 'host' with your hostname
                Diffusion.sessions().open("ws://host:port", sessionHandler );
            }
    You can connect securely, using Secure Sockets Layer (SSL):
        Diffusion.sessions().open("wss://host:port", sessionHandler);
    Or you can connect with a principal and credentials if that principal is assigned a role with the select_topic and read_topic permissions:
    Diffusion.sessions().principal("principal").password("password").open("wss://host:port", sessionHandler);
    Replace the host, port, principal, and password values with your own information.
  10. Override the onDestroy method of the MainActivity class to close the session with the Diffusion server.
            if ( sessionHandler != null ) {
                sessionHandler.close();
                sessionHandler = null;
            }
            super.onDestroy();
  11. Compile and run your client.

The client outputs the value to the log console every time the value of the foo/counter topic is updated. You can update the value of the foo/counter topic by creating a publishing client to update the topic. To create and publish to the foo/counter topic, you require a user with the modify_topic and update_topic permissions. For more information, see Start publishing with Android.

Full example

The completed MainActivity class contains the following code:
package com.pushtechnology.demo.subscribe;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.callbacks.ErrorReason;
import com.pushtechnology.diffusion.client.content.Content;
import com.pushtechnology.diffusion.client.features.Topics;
import com.pushtechnology.diffusion.client.features.Topics.TopicStream;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.session.SessionFactory;
import com.pushtechnology.diffusion.client.types.UpdateContext;

public class MainActivity extends AppCompatActivity {
    /**
     * A topic stream that prints updates to logcat.
     */
    private static class TopicStreamLogcat extends TopicStream.Default {
        @Override
        public void onTopicUpdate(String topic, Content content,
                                  UpdateContext context) {

            Log.i("Topic Stream", topic + ":   " + content.asString());
        }
    }

    /**
     * A session handler that maintains the diffusion session.
     */
    private class SessionHandler implements SessionFactory.OpenCallback {
        private Session session = null;

        @Override
        public void onOpened(Session session) {
            this.session = session;

            // Get the Topics feature to subscribe to topics
            final Topics topics = session.feature( Topics.class );

            // Add a new topic stream for 'foo/counter'
            topics.addTopicStream(">foo/counter", new TopicStreamLogcat());

            // Subscribe to the topic 'foo/counter'
            topics.subscribe("foo/counter",
                    new Topics.CompletionCallback.Default());
        }

        @Override
        public void onError(ErrorReason errorReason) {
            Log.e( "Diffusion", "Failed to open session because: " + errorReason.toString() );
            session = null;
        }

        public void close() {
            if ( session != null ) {
                session.close();
            }
        }
    }

    private SessionHandler sessionHandler = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if ( sessionHandler == null ) {
            sessionHandler = new SessionHandler();

            // Connect anonymously
            // Replace 'host' with your hostname
            Diffusion.sessions().open("ws://host:port", sessionHandler );
        }
    }

    @Override
    protected void onDestroy() {
        if ( sessionHandler != null ) {
            sessionHandler.close();
            sessionHandler = null;
        }
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}