Table of Contents
Just a second...

Start publishing with Android

Create an Android™ client that publishes data through topics on the Diffusion™ server.

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

You also require a named user that has a role with the modify_topic and update_topic permissions. For example, the "ADMINISTRATOR" role. For more information about roles and permissions, see Role-based authorization.

This example steps through the lines of code required to publish 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.features.Topics;
    import com.pushtechnology.diffusion.client.features.control.topics.TopicControl;
    import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.AddCallback;
    import com.pushtechnology.diffusion.client.features.control.topics.TopicUpdateControl;
    import com.pushtechnology.diffusion.client.features.control.topics.TopicUpdateControl.Updater.UpdateCallback;
    import com.pushtechnology.diffusion.client.session.Session;
    import com.pushtechnology.diffusion.client.session.SessionFactory;
    import com.pushtechnology.diffusion.client.topics.details.TopicType;
    
    import java.util.concurrent.CountDownLatch;
    
    
    public class MainActivity extends AppCompatActivity {
    
    }

    The com.pushtechnology.diffusion.client packages contain the classes to use to interact with the Diffusion server. The java.util.concurrent.CountDownLatch class is used to simplify this example by making it more synchronous. However, the Diffusion API is designed to be most powerful when used asynchronously.

  5. 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();
                }
            }
        }
  6. In the onOpened method, create the code required to create the foo/counter topic and update it with an incrementing value.
    1. Get the TopicControl and TopicUpdateControl features.
          // Get the TopicControl and TopicUpdateControl feature
          final TopicControl topicControl = session.feature(TopicControl.class);
      
          final TopicUpdateControl updateControl = session
                          .feature(TopicUpdateControl.class);
    2. Use the TopicControl feature to create the foo/counter topic.
          final CountDownLatch waitForStart = new CountDownLatch(1);
      
                  // Create a single value topic 'foo/counter'
                  topicControl.addTopic("foo/counter", TopicType.SINGLE_VALUE,
                          new AddCallback.Default() {
                              @Override
                              public void onTopicAdded(String topicPath) {
                                  waitForStart.countDown();
                              }
                          });
      
                  // Wait for the onTopicAdded() callback.
                  try {
                      waitForStart.await();
                  } catch (InterruptedException e) {
                      Log.e("Diffusion", e.getStackTrace().toString());
                  }
      This example uses a CountDownLatch to wait until the topic is successfully added. This approach is used to simplify the example and is not recommended for production clients.
    3. Loop once a second updating the foo/counter topic with an incrementing count from 0 to 1000.
      Use the updateControl.updater().update() method to update a topic without locking that topic.
       // Update the topic
                  for (int i = 0; i < 1000; ++i) {
      
                      // Use the non-exclusive updater to update the topic without locking
                      // it
                      updateControl.updater().update("foo/counter", Integer.toString(i),
                              new UpdateCallback.Default());
      
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          Log.e("Diffusion", e.getStackTrace().toString());
                      }
                  }
  7. In the MainActivity class, declare an instance of session handler.
    private SessionHandler sessionHandler = null;
  8. 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 using a principal with 'modify_topic' and 'update_topic'
            // permissions
            Diffusion.sessions().principal("principal")
                                .password("password")
                                .open("ws://host:port", sessionHandler );
        }
    Or you can connect securely, using Secure Sockets Layer (SSL):
    Diffusion.sessions().principal("principal").password("password").open("wss://host:port", sessionHandler);
    Replace the host, port, principal, and password values with your own information.
  9. 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();
  10. Compile and run your client.

The client publishes a value to the foo/counter topic every second. You can subscribe to the foo/counter topic by creating a client to subscribe to the topic. For more information, see Start subscribing with Android.

Full example

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

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.features.Topics;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl;
import com.pushtechnology.diffusion.client.features.control.topics.TopicControl.AddCallback;
import com.pushtechnology.diffusion.client.features.control.topics.TopicUpdateControl;
import com.pushtechnology.diffusion.client.features.control.topics.TopicUpdateControl.Updater.UpdateCallback;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.session.SessionFactory;
import com.pushtechnology.diffusion.client.topics.details.TopicType;

import java.util.concurrent.CountDownLatch;

public class MainActivity extends AppCompatActivity {

    /**
     * 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 TopicControl and TopicUpdateControl feature
            final TopicControl topicControl = session.feature(TopicControl.class);

            final TopicUpdateControl updateControl = session
                    .feature(TopicUpdateControl.class);

            final CountDownLatch waitForStart = new CountDownLatch(1);

            // Create a single value topic 'foo/counter'
            topicControl.addTopic("foo/counter", TopicType.SINGLE_VALUE,
                    new AddCallback.Default() {
                        @Override
                        public void onTopicAdded(String topicPath) {
                            waitForStart.countDown();
                        }
                    });

            // Wait for the onTopicAdded() callback.
            try {
                waitForStart.await();
            } catch (InterruptedException e) {
                Log.e("Diffusion", e.getStackTrace().toString());
            }

            // Update the topic
            for (int i = 0; i < 1000; ++i) {

                // Use the non-exclusive updater to update the topic without locking
                // it
                updateControl.updater().update("foo/counter", Integer.toString(i),
                        new UpdateCallback.Default());

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Log.e("Diffusion", e.getStackTrace().toString());
                }
            }
        }

        @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 using a principal with 'modify_topic' and 'update_topic'
            // permissions
            Diffusion.sessions().principal("principal")
                                .password("password")
                                .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);
    }
}