Developer Relations Engineer, PubNub
IN THIS ARTICLE
    GitHubGitHub

    GitHub Repo

    GitHub Repo

    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

    PubNub Signals is small message payload messaging, no greater than 30 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:

    1. Typing indicators in a chat app
    2. GPS lat/long updates (what we’ll cover in this tutorial)
    3. Sensor streaming updates for IoT devices
    4. Stats for gaming applications

    When to Use Signals Instead of Publish?

    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 PubNub Access Manager.

    Unlike Publish, there are some limitations to using Signals:

    1. Messages sent with Signals are not replicated to all global data centers
    2. Messages are not stored in PubNub History for later retrieval; only the most recent message can be fetched
    3. PubNub Push notifications can’t be invoked
    4. Access to PubNub Functions is disabled by default and can only be enabled by PubNub Support

    Geolocation App with PubNub 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.

    Geolocation App Screenshot

    Note: This app DOES NOT use your location!

    Get Your API Keys

    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.

    Set Up PubNub’s Event Listener

    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.

    Set Up Google Maps Event Listener

    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 30 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 30 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.

    Place the Marker 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));
    }

    Run the Geolocation App

    In Android Studio, run the app in two emulators to see the markers change location in realtime!

    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.

    Try PubNub today!

    Build realtime applications that perform reliably and securely, at global scale.
    Try Our APIs
    Try PubNub today!
    More From PubNub