1

I have a service that gets the user's location and broadcasts the latitude and longitude in an intent.

I believe that I need the service to be a started service (as opposed to bound service), because I would like for it to be able to send a push notification to the user when a new geoFire entry from firebase enters their radius even when the app is closed.

Currently, the service is set up to broadcast the location.

Given that the location service will be a started service, I don't know how to access the broadcast from two separate activities.

I believe that I could achieve this if it were a bound service, but since I want it to stay alive indefinitely, I'm not sure what to do.

Here is a minimal example that demonstrates my issue.

Specifically, I can get the latitude and longitude to display on the first activity by registering a broadcast receiver, but I can't get the latitude and longitude to display on the second activity by registering a separate broadcast receiver.

I have read Android's documentation on Services but still don't really know what I'm supposed to do to resolve this problem.

I've been testing this all on an emulator from Android Studio: Nexus 5X API 25 x86.

UPDATE Nov. 8, 2017: I've updated the github project to contain the EventBus solution provided below. It is in the eventBus branch. The master branch still contains the ualtered, problematic code pertaining to the question.

To view:

git clone https://github.com/Atticus29/locationServiceMCV.git
git checkout eventBus

Then, open AndroidStudio or IDE of choice and view/run as you normally would.

Atticus29
  • 4,190
  • 18
  • 47
  • 84
  • 1
    If the activities and the service live in the same app (same process) there's no need for broadcasting intents. You can just use a singleton that is written by the Service and read by any reader (your activities in this case). – m0skit0 Nov 07 '17 at 00:03
  • @m0skit0 how would I implement what you're suggesting? – Atticus29 Nov 07 '17 at 00:44

1 Answers1

3

Broadcasting the results is one way to solve this issue. But if you're willing to add a lib on your project I would strongly recommend Green Robot's EventBus. It's a very lightweight lib, as it's fast. Also, it's simple to post complex objects through it without having to implement the Parcelable interface.

This lib works on a publisher/subscriber fashion, where in your case, both Activities would be the subscribers, and the Service would be the publisher.

Event Bus

First of all, you have to add the dependency on your build.gradle file as below.

implementation 'org.greenrobot:eventbus:3.0.0'

If you're on a Kotlin project, also add this dependency:

kapt 'org.greenrobot:eventbus-annotation-processor:3.0.1'

Then, define an Event class that will be responsible to carry your data through the app. Note that this could be done from a Service to an Activity. From a Fragment to another. Between Activities, and so on.

public class MessageEvent { 
    public double lat;
    public double lng;
    // Add additional fields here if needed

    public MessageEvent(double lat, double lng) {
        this.lat= lat;
        this.lng = lng;
    }
}

After that, you have to subscribe to those events on your Activity.

public class MyActivity extends AppCompatActivity {
    // ...

     @Override
     public void onResume() {
         super.onResume();
         // This line will register your Activity to the EventBus
         // making sure that all the methods annotated with @Subscribe 
         // will be called if their specific Events are posted.
         EventBus.getDefault().register(this);
     }

     @Override
     public void onPause() {
         super.onPause();
         // This line will unregister your Activity.
         // It's a good practice to put this on the onPause() method
         // to make your event handling system tied to the Activity lifecycle.
         EventBus.getDefault().unregister(this);
     }

    // The threadMode MAIN makes sure this method is called on the main Thread. 
    // But you could also set it up to be called on other threads if needed. Check the docs for more info.
    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)  
    public void onMessageEvent(MessageEvent event) {
        /* Call this line below if you want to remove the sticky event.
        *  That will prevent that this event will be seen by other subscribers once they subscribe.
        *  In your specific use case, you don't have to remove the sticky event here. 
        */
        // EventBus.getDefault().removeStickyEvent(event);
        double lat = event.lat;
        double lng = event.lng;
        // Do whatever you want with the data.
    };
}

With that implemented, you're ready to post your events. Now, inside your Service, call the following code when you get the new Lat/Lng information.

EventBus.getDefault().postSticky(new MessageEvent(lat,lng));

You can read more on how to setup and customize the EventBus on the docs, or on this tutorial.

Mauker
  • 11,237
  • 7
  • 58
  • 76
  • thanks so much! I've successfully implemented your suggestion and demonstrated successful use of the EventBus on my first activity. However, my second activity still does not seem to be getting it. Any suggestions? I have the implementation of your example in the "eventBus" branch of the repo linked in the beginning of this question. – Atticus29 Nov 07 '17 at 03:42
  • 1
    Ok, I got it. A Sticky event will stay on the EventBus for as long as you want it to be. Usually, I remove it the first time I read it, but that doesn't fit your use case. The problem is on this line: https://github.com/Atticus29/locationServiceMCV/blob/eventBus/app/src/main/java/fisherdynamic/locationservicemcv/MainActivity.java#L78 - Remove it on both Activities. You could then call `EventBus.getDefault().removeAllStickyEvents()` once your Service is destroyed. – Mauker Nov 07 '17 at 12:50
  • This way, both of your Activities will be able to read the sticky event once they subscribe to the EventBus, getting the latest Lat Lng event posted by the Service. – Mauker Nov 07 '17 at 12:57
  • That did it, @Mauker! Thank you! – Atticus29 Nov 08 '17 at 18:38
  • Do we need to refine this answer, or do we trust that folks will read into these comments for the full answer? – Atticus29 Nov 08 '17 at 18:39
  • 1
    I've edited the answer already to reflect your use case, with comments on the code :) – Mauker Nov 08 '17 at 18:55