Not all message sizes are the same. For example, the size for sending a text message is much greater than sending GPS coordinates. Not only that, text messages must be encrypted and stored in history for later retrieval while coordinates are useful for a brief moment of time. It seems fair that larger payloads should be priced higher than smaller payloads. With this in mind, PubNub has launched Signals.
PubNub Signals is small message payload messaging, no greater than 64 bytes, that offers a low-cost data delivery rate while still leveraging PubNub’s secure and reliable Data Stream Network. Some use cases for Signals include:
If your application needs to send a stream of messages to instruct or inform your application, where the content of each message is not as important as the stream of data, then use Signals. Signals uses the core Pub/Sub features such as channels groups and Access Manager.
Unlike Publish, there are some limitations to using Signals:
To get a better understanding of what you can do with PubNub Signals, let’s go over a simple geolocation app in Android. For this app, a marker will initially be placed in San Francisco. The user can move and place the marker anywhere they please, and the coordinates will be sent to a global channel using Signals. The marker will update for everyone connected to the channel.
Note: This app DOES NOT use your location!
Sign up for your free PubNub API keys. You can send up to 1 million free messages a month! Use the form below to get your keys:
Once you have your keys, add them to initiPubNub() in MainActivity.java:
// Variables private GoogleMap mMap; private PubNub pubnub; private Marker marker; private Boolean isMarkerPlaced = false; // Initialize PubNub and set up a listener public void initPubNub(){ PNConfiguration pnConfiguration = new PNConfiguration(); pnConfiguration.setPublishKey("Your_Pub_Key_Here"); pnConfiguration.setSubscribeKey("Your_Sub_Key_Here"); pnConfiguration.setSecure(true); pubnub = new PubNub(pnConfiguration); ... }
Besides the Pub/Sub keys, you also need to get a Google Maps API key. Once you have the key, go to the debug directory, under src, and add it to the file google_maps_api.xml.
<resources> <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">YOUR_KEY_HERE</string> </resources>
Now that we have all the keys set up in the app, let’s go over the app.
After initializing PubNub, we set up an event listener to listen for messages that arrive on the channel. Inside the listener, we implement the method signal().
// Listen to messages that arrive in the channel pubnub.addListener(new SubscribeCallback() { @Override public void status(PubNub pub, PNStatus status) { } @Override public void message(PubNub pub, final PNMessageResult message) { } @Override public void presence(PubNub pub, PNPresenceEventResult presence) { } @Override public void signal(PubNub pubnub, final PNMessageResult signal) { System.out.println("Message: " + signal.getMessage()); runOnUiThread(new Runnable() { @Override public void run() { try { JsonArray payload = signal.getMessage().getAsJsonArray(); placeMarker(payload); } catch (Exception e) { e.printStackTrace(); } } }); } });
Since we are no longer publishing the GPS coordinates with PubNub Publish, the method message() is empty. Inside of the signal() method, the message payload is received, converted into a JsonArray, and placeMarker() is called to update the current marker with the new coordinates in the map. We’ll come back to this method shortly.
Below addListener(), subscribe to the global channel geolocation_channel .
// Subscribe to the global channel pubnub.subscribe() .channels(Arrays.asList("geolocation_channel")) .execute();
Next, let’s set up the marker on the map and add a drag and drop event listener for the marker.
As mentioned earlier, the marker is initially placed in San Francisco. To add the marker in the map, placeMarker() is called with the marker coordinates as the argument. Before we get to this method, let’s complete the method onMapReady() which is triggered when Google Maps is ready to use.
public void onMapReady(GoogleMap googleMap) { mMap = googleMap; // Initial payload coordinates in S.F.♥︎ JsonArray payload = new JsonArray(); payload.add(37.782486); payload.add(-122.395344); placeMarker(payload); }
We need to add an event listener that is triggered when the marker is dragged anywhere in the map. Add the following code to onMapReady():
// Initial payload coordinates in S.F.♥︎ ... // Listener for when marker is dragged to another location mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() { @Override public void onMarkerDrag(Marker arg0) { Log.d("Marker", "Dragging"); } @Override public void onMarkerDragEnd(Marker arg0) { Log.d("Marker", "Finished"); } @Override public void onMarkerDragStart(Marker arg0) { Log.d("Marker", "Started"); } });
Once the user has placed the marker in a new location, the Lat/Long coordinates are sent to the global channel to update the marker placement for everyone connected. To do so, we get the new position of the marker, add it to a JsonArray, and send the payload to the channel. Since we can only send 64 bytes, we format the coordinate values up to 6 digits after the decimal point, which is the same format that Google Maps uses. We do all of this logic inside of onMarkerDragEnd():
@Override public void onMarkerDragEnd(Marker arg0) { Log.d("Marker", "Finished"); // Get coordinate values up to 6 decimal numbers DecimalFormat decimalFormat = new DecimalFormat("0.######"); JsonArray payload = new JsonArray(); payload.add(decimalFormat.format(marker.getPosition().latitude)); // Get lat coord. payload.add(decimalFormat.format(marker.getPosition().longitude)); // Get long coord. // Message Payload size for PubNub Signals is limited to 64 bytes pubnub.signal() .channel("geolocation_channel") .message(payload) .async(new PNCallback<PNPublishResult>() { @Override public void onResponse(PNPublishResult result, PNStatus status) { // Error if(status.isError()) { System.out.println("Error- pub status code: " + status.getStatusCode()); } } }); }
If the payload is successfully sent and received on the channel, the marker is placed on the map.
In the app, we call placeMarker() twice to add the marker in the initial location and to update the marker in a new location. In order for the method to know which of the two things to do, we use the boolean variable isMarkerPlaced. This variable is initialized to false. It is set to true once the maker has been placed.
// Place marker on the map in the specified location public void placeMarker(JsonArray loc){ //LatLng only accepts arguments of type Double Double lat = loc.get(0).getAsDouble(); Double lng = loc.get(1).getAsDouble(); LatLng newLoc = new LatLng(lat,lng); if(isMarkerPlaced){ // Change position of the marker marker.setPosition(newLoc); marker.setTitle(newLoc.toString()); } else{ // Add a marker to the map in the specified location marker = mMap.addMarker(new MarkerOptions().position(newLoc).title(newLoc.toString()).draggable(true)); isMarkerPlaced = true; } // Move the camera to the location of the marker mMap.moveCamera(CameraUpdateFactory.newLatLng(newLoc)); }
In Android Studio, run the app in two emulators to see the markers change location in real time!
Now that you know how to send GPS coordinates using PubNub Signals, check out other ways to use Signals, such as implementing Typing Indicators in a Chat App.
Have suggestions or questions about the content of this post? Reach out at devrel@pubnub.com.
There are common underlying technologies for a dating app, and in this post, we’ll talk about the major technologies and designs...
Michael Carroll
How to use geohashing, JavaScript, Google Maps API, and BART API to build a real-time public transit schedule app.
Michael Carroll
How to track and stream real-time vehicle location on a live-updating map using EON, JavaScript, and the Mapbox API.
Michael Carroll