Android Quickstart
In this Quickstart, you'll learn how to build your first Android app that sends and receives messages, and how to use status and presence events to enhance your real-time application.
Sample app Quickstart | SDK Getting Started |
---|---|
PubNub Account
Sign in or create an account to create an app on the Admin Portal and get the keys to use in this quickstart.
Download Sample App
You can clone the repository that contains the files we will use in this quickstart. Remember to replace the publish and subscribe key placeholders with your own keys.
https://github.com/pubnub/android-quickstart-platform
Project Setup
To build your own Android project manually, use the following steps:
In Android Studio, create a new Empty Activity project named
pnquickstart
.Include the PubNub SDK using Gradle.
Insert the PubNub
implementation group
dependency at the end of thedependencies
section inbuild.gradle (Module: app)
under the Gradle Scripts folder of your project. Your list of existing dependencies may differ.dependencies { // some existing dependencies implementation fileTree(dir: 'libs', include: ['*.jar']) // add PubNub Android-Java SDK here at that bottom implementation group: 'com.pubnub', name: 'pubnub-gson', version: '4.+' }
Click Sync Now at the top right of the file window.
In your project's
manifests
folder, add the following permissions toAndroidManifest.xml
:<manifest> ...existing content... <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> </manifest>
Add Project Files
Add the following code in the files in your project
Activity UI XML code
Open the
activity_main.xml
file, located in theres/layout
folder. (It may open in the visual canvas view.)Click the menu button (three horizontal lines) at the top right of the file window, and open the XML source code view.
Overwrite all existing XML code with the code below, and save your changes.
This defines a simple UI for the app:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="24dp"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/btn_submit_message" android:layout_alignParentTop="true"> <TextView android:id="@+id/messages_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:enabled="true" android:gravity="start|top" android:importantForAutofill="no" tools:ignore="LabelFor" /> </ScrollView> <Button android:id="@+id/btn_submit_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/entry_update_text" android:layout_marginStart="40dp" android:layout_marginTop="10dp" android:layout_marginEnd="40dp" android:minWidth="140sp" android:onClick="onClick" android:text="Submit Update to The Guide" android:textSize="14sp" tools:ignore="HardcodedText" /> <EditText android:id="@+id/entry_update_text" android:layout_width="match_parent" android:layout_height="40dp" android:layout_alignParentBottom="true" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:ems="10" android:hint="enter update for Earth" android:importantForAutofill="no" android:inputType="text" android:text="Mostly Harmless." android:textSize="14sp" tools:ignore="HardcodedText" /> </RelativeLayout>
Return to the canvas view to see the new user interface.
Keep it simple
The objective here is to keep things as simple as possible so that the UI code doesn't hinder the process of learning how to use PubNub. A real-world app would better leverage the MVC features of the Android platform.
Activity Class Java Code
Add the following imports to
MainActivity.java
:import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; import java.util.Arrays; import androidx.appcompat.app.AppCompatActivity; import com.google.gson.JsonObject; import com.pubnub.api.PNConfiguration; import com.pubnub.api.PubNub; import com.pubnub.api.callbacks.PNCallback; import com.pubnub.api.callbacks.SubscribeCallback; import com.pubnub.api.enums.PNStatusCategory; import com.pubnub.api.models.consumer.PNPublishResult; import com.pubnub.api.models.consumer.PNStatus; import com.pubnub.api.models.consumer.pubsub.PNMessageResult; import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult; import com.pubnub.api.models.consumer.pubsub.PNSignalResult; import com.pubnub.api.models.consumer.pubsub.message_actions.PNMessageActionResult; import com.pubnub.api.models.consumer.objects_api.channel.PNChannelMetadataResult; import com.pubnub.api.models.consumer.objects_api.membership.PNMembershipResult; import com.pubnub.api.models.consumer.objects_api.uuid.PNUUIDMetadataResult;
Replace the key placeholders
Remember to replace the "myPublishKey" and "mySubscribeKey" placeholders with your own PubNub publish and subscribe keys.
Replace the current class code with the following, and make sure that your Activity class is named
MainActivity
:public class MainActivity extends AppCompatActivity implements View.OnClickListener { private EditText entryUpdateText; private TextView messagesText; private PubNub pubnub; private String theChannel = "the_guide"; private String theEntry = "Earth"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PNConfiguration pnConfiguration = new PNConfiguration(); // replace the key placeholders with your own PubNub publish and subscribe keys pnConfiguration.setPublishKey("myPublishKey"); pnConfiguration.setSubscribeKey("mySubscribeKey"); pnConfiguration.setUuid("ReplaceWithYourClientIdentifier"); pubnub = new PubNub(pnConfiguration); pubnub.addListener(new SubscribeCallback() { @Override public void message(PubNub pubnub, PNMessageResult event) { JsonObject message = event.getMessage().getAsJsonObject(); String entryVal = message.get("entry").getAsString(); String updateVal = message.get("update").getAsString(); displayMessage("[MESSAGE: received]",entryVal + ": " + updateVal); } @Override public void status(PubNub pubnub, PNStatus event) { displayMessage("[STATUS: " + event.getCategory() + "]", "connected to channels: " + event.getAffectedChannels()); if (event.getCategory().equals(PNStatusCategory.PNConnectedCategory)){ submitUpdate(theEntry, "Harmless."); } } @Override public void presence(PubNub pubnub, PNPresenceEventResult event) { displayMessage("[PRESENCE: " + event.getEvent() + ']', "uuid: " + event.getUuid() + ", channel: " + event.getChannel()); } // even if you don't need these handler, you still have include them // because we are extending an Abstract class @Override public void signal(PubNub pubnub, PNSignalResult event) { } @Override public void uuid(PubNub pubnub, PNUUIDMetadataResult pnUUIDMetadataResult) { } @Override public void channel(PubNub pubnub, PNChannelMetadataResult pnChannelMetadataResult) { } @Override public void membership(PubNub pubnub, PNMembershipResult pnMembershipResult) { } @Override public void messageAction(PubNub pubnub, PNMessageActionResult event) { } @Override public void file(PubNub pubnub, PNFileEventResult pnFileEventResult) { } }); pubnub.subscribe().channels(Arrays.asList(theChannel)).withPresence().execute(); entryUpdateText = findViewById(R.id.entry_update_text); messagesText = findViewById(R.id.messages_text); } protected void submitUpdate(String anEntry, String anUpdate) { JsonObject entryUpdate = new JsonObject(); entryUpdate.addProperty("entry", anEntry); entryUpdate.addProperty("update", anUpdate); pubnub.publish().channel(theChannel).message(entryUpdate).async( new PNCallback<PNPublishResult>() { @Override public void onResponse(PNPublishResult result, PNStatus status) { if (status.isError()) { status.getErrorData().getThrowable().printStackTrace(); } else { displayMessage("[PUBLISH: sent]", "timetoken: " + result.getTimetoken()); } } }); } protected void displayMessage(String messageType, String aMessage) { String newLine = "\n"; final StringBuilder textBuilder = new StringBuilder() .append(messageType) .append(newLine) .append(aMessage) .append(newLine).append(newLine) .append(messagesText.getText().toString()); runOnUiThread(new Runnable() { @Override public void run() { messagesText.setText(textBuilder.toString()); } }); } @Override public void onClick(View view) { submitUpdate(theEntry, entryUpdateText.getText().toString()); entryUpdateText.setText(""); } }
Run the app
If this is your first Android Studio project, create an emulator before you follow the steps below:
1. Click the Run button. You should see an Android emulator that displays a screen similar to this: The UI is simple, and the message display area is initially obscured by the keyboard. Dismiss the keyboard to see more of the messages. The app publishes a message at startup, and displays some other messages and events. 2. Submit a new entry. A new entry update is auto populated for you: "Mostly Harmless." Change the text if you'd like, then click the Submit Update to the Guide button to publish the new update. The new update appears at the top of the current messages, while the older messages scroll down, and the entry update field is cleared for you to enter something new. | ![]() |
Message display order can vary
This code is executed asynchronously, so the order in which the [MESSAGE: received] and [PUBLISH: sent] messages appear may vary.
Walkthrough
Let's review exactly what is happening for all this to work properly.
Include the PubNub SDK
Using Gradle, you included the PubNub Android-Java SDK by declaring a dependency on it in the build.gradle
file.
Additionally, you added some permissions to allow the app to access the internet to the AndroidManifest.xml
file (so you can connect to PubNub Platform).
Create the UI
The UI is intentionally simple to reduce the amount of code necessary to bind the message updates to the UI components. The UI is built using XML which can be generated using the IDE's visual UI designer tool. You just copy/pasted the XML results of a generated UI using that tool. Each UI element has an ID that your Java code can use to reference and update those UI elements.
Set up the Activity code
The remainder of the steps take place in the MainActivity.java
class file. In a real-world app, you would implement different pieces of this code in different class files, following an MVVM (Model, View, ViewModel) design pattern for Android apps. For simplicity, this quickstart keeps everything in the MainActivity
class.
Here is an overview of what is happening in the MainActivity
class:
onCreate
is an Android Activity method that gets called when the app is first started. This is where you initialize the PubNub object, add event listeners, and subscribe to a channel(s).displayMessages
updates the message UI when new messages or events are received.onClick
is an Android button click handler event that you bind to the button to submit new entry updates.
Initialize the PubNub object
The PubNub object allows you to make PubNub API calls, like publish
, subscribe
, and more. There are more configuration properties than what you see here, but this is all you need for this quickstart. Of course, you would use your own publish and subscribe keys below. It's important to set the uuid
for the client. This is typically received from your server after the client logs in successfully.
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.setPublishKey("myPublishKey");
pnConfiguration.setSubscribeKey("mySubscribeKey");
pnConfiguration.setUuid("ReplaceWithYourClientIdentifier");
pubnub = new PubNub(pnConfiguration);
Proper PubNub initialization
If your app has several views that require the PubNub object, initialize it in the MainActivity
class and pass between views using Intents. However, if PubNub is only required in seldom-used sections of your app, you might just initialize it on demand in that view. You may also implement other common strategies for building your UIs and passing data.
Listen for Messages and Events
The addListener
code has handler methods that receive all published messages and other events.
pubnub.addListener(new SubscribeCallback() {
// handlers go here
});
This app is only concerned with message
, status
, and presence
events. There are several other handlers that have no implementation, but because you're instantiating an abstract Java class, SubscribeCallback
, you need to override all the declared abstract methods of that class. You'll use these for other features of PubNub.
Receiving Messages
The message
handler receives all messages published to all channels subscribed by this client. When a message arrives, you're simply appending the content to the top of the messages UI component.
@Override
public void message(PubNub pubnub, PNMessageResult event) {
JsonObject message = event.getMessage().getAsJsonObject();
String entryVal = message.get("entry").getAsString();
String updateVal = message.get("update").getAsString();
displayMessage("[MESSAGE: received]",entryVal + ": " + updateVal);
}
Receiving Status Events
The status
handler allows you to monitor and manage the connection to the PubNub platform and channels. When the client subscribes to a channel, it receives a PNConnectedCategory
status event to indicate a successful channel connection. You're using this event to submit an initial entry update (publishing a message to a channel).
@Override
public void status(PubNub pubnub, PNStatus event) {
displayMessage("[STATUS: " + event.getCategory() + "]",
"connected to channels: " + event.getAffectedChannels());
if (event.getCategory().equals(PNStatusCategory.PNConnectedCategory)){
submitUpdate(theEntry, "Harmless.");
}
}
Receiving Presence Events
The presence
handler allows you to monitor when this and other clients join and leave channels. The subscribe
call's withPresence
parameter indicates that the client wishes to receive presence events on the subscribed channels. If you're running only one instance of the app, you'll only receive a join
event. If you started a second instance, or used another client such as the PubNub Dev Console, you would also see a join
event for that client. You would also see a leave
event when the other client unsubscribed from a channel, or a timeout
event if it went offline without first unsubscribing.
@Override
public void presence(PubNub pubnub, PNPresenceEventResult event) {
displayMessage("[PRESENCE: " + event.getEvent() + ']',
"uuid: " + event.getUuid() + ", channel: " + event.getChannel());
}
Successive App Run Behavior
If you test run the app multiple times within a few minutes, you may not see the presence join event appear because the client's UUID is the same as the previous run and is still considered active from the previous run.
Subscribe to a Channel
This subscribe
call opens a connection to PubNub and waits for messages to be published to this channel. You can subscribe to more than one channel at a time, but you only need the one for this quickstart. The withPresence()
parameter enables presence events to be sent for the channel being subscribed in this call.
pubnub.subscribe().channels(Arrays.asList(theChannel)).withPresence().execute();
Publish Messages
The submitUpdate
method is invoked when you click the "Submit Update to the Guide" button. This method wraps the publish
call so that you can call it from anywhere in the Activity in a standard way. The messages that this client publishes to this channel will be received by this and other clients subscribed to this channel, in the message
handler. The success of a publish
event is updated in the message UI component with the publish timetoken
value.
protected void submitUpdate(String anEntry, String anUpdate) {
JsonObject entryUpdate = new JsonObject();
entryUpdate.addProperty("entry", anEntry);
entryUpdate.addProperty("update", anUpdate);
pubnub.publish().channel(theChannel).message(entryUpdate)
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if (status.isError()) {
status.getErrorData().getThrowable().printStackTrace();
}
else {
displayMessage("[PUBLISH: sent]",
"timetoken: " + result.getTimetoken());
entryUpdateText.setText("");
}
}
});
}
Display Messages
The displayMessage
method handles all updates to the messages UI component in a standard way. Any time a new message or event needs to be displayed, it's prepended to the existing messages so that the latest update is always at the top. In a real-world app, you would have more sophisticated data binding using a list or table element that leverages Android MVVM design patterns using Intents, Services, and other components.
protected void displayMessage(String messageType, String aMessage) {
final String newLine = "\n";
final StringBuilder textBuilder = new StringBuilder()
.append(messageType)
.append(newLine)
.append(aMessage)
.append(newLine).append(newLine)
.append(messagesText.getText().toString());
runOnUiThread(new Runnable() {
@Override
public void run() {
messagesText.setText(textBuilder.toString());
}
});
}
The runOnUiThread()
method is required any time you want to update your UI from a background thread.
Next Steps
Now that you have your Android app up and running with PubNub, learn more about what else you can do with Channels. To discover what else the Android SDK offers, go to the Android SDK Reference.