Skip to content

Instantly share code, notes, and snippets.

@blackcj
Last active February 8, 2022 12:33
Show Gist options
  • Save blackcj/20efe2ac885c7297a676 to your computer and use it in GitHub Desktop.
Save blackcj/20efe2ac885c7297a676 to your computer and use it in GitHub Desktop.
Background location services.
/**
*
* BackgroundLocationService used for tracking user location in the background.
* @author cblack
*/
public class BackgroundLocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
IBinder mBinder = new LocalBinder();
private GoogleApiClient mGoogleApiClient;
private PowerManager.WakeLock mWakeLock;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private Boolean servicesAvailable = false;
public class LocalBinder extends Binder {
public BackgroundLocationService getServerInstance() {
return BackgroundLocationService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
mInProgress = false;
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(Constants.UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
servicesAvailable = servicesConnected();
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
setUpLocationClientIfNeeded();
}
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
protected synchronized void buildGoogleApiClient() {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
return true;
} else {
return false;
}
}
public int onStartCommand (Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
/*
WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring.
This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find.
*/
if (this.mWakeLock == null) { //**Added this
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
}
if (!this.mWakeLock.isHeld()) { //**Added this
this.mWakeLock.acquire();
}
if(!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress)
{
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
private void setUpLocationClientIfNeeded()
{
if(mGoogleApiClient == null)
buildGoogleApiClient();
}
// Define the callback method that receives location updates
@Override
public void onLocationChanged(Location location) {
// Report to the UI that the location was updated
String msg = Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d("debug", msg);
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ":" + msg, Constants.LOCATION_FILE);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public String getTime() {
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return mDateFormat.format(new Date());
}
public void appendLog(String text, String filename)
{
File logFile = new File(filename);
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.servicesAvailable && this.mGoogleApiClient != null) {
this.mGoogleApiClient.unregisterConnectionCallbacks(this);
this.mGoogleApiClient.unregisterConnectionFailedListener(this);
this.mGoogleApiClient.disconnect();
// Destroy the current location client
this.mGoogleApiClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
super.onDestroy();
}
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
@Override
public void onConnected(Bundle bundle) {
// Request location updates using static settings
Intent intent = new Intent(this, LocationReceiver.class);
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
mLocationRequest, this); // This is the changed line.
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE);
}
/*
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
@Override
public void onConnectionSuspended(int i) {
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mGoogleApiClient = null;
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
}
/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
// If no resolution is available, display an error dialog
} else {
}
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.blackcj.locationtracker"
minSdkVersion 18
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:22.2.1'
compile 'com.google.android.gms:play-services-location:8.4.0'
}
public final class Constants {
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// Update frequency in seconds
private static final int UPDATE_INTERVAL_IN_SECONDS = 60;
// Update frequency in milliseconds
public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
// The fastest update frequency, in seconds
private static final int FASTEST_INTERVAL_IN_SECONDS = 60;
// A fast frequency ceiling in milliseconds
public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
// Stores the lat / long pairs in a text file
public static final String LOCATION_FILE = "sdcard/location.txt";
// Stores the connect / disconnect data in a text file
public static final String LOG_FILE = "sdcard/log.txt";
public static final String RUNNING = "runningInBackground"; // Recording data in background
public static final String APP_PACKAGE_NAME = "com.blackcj.locationtracker";
/**
* Suppress default constructor for noninstantiability
*/
private Constants() {
throw new AssertionError();
}
}
public class LocationLoggerServiceManager extends BroadcastReceiver {
private SharedPreferences mPrefs;
public static final String TAG = "LLoggerServiceManager";
@Override
public void onReceive(Context context, Intent intent) {
// Make sure we are getting the right intent
if( "android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
boolean mUpdatesRequested = false;
// Open the shared preferences
mPrefs = context.getSharedPreferences(
Constants.APP_PACKAGE_NAME, Context.MODE_PRIVATE);
/*
* Get any previous setting for location updates
* Gets "false" if an error occurs
*/
if (mPrefs.contains(Constants.RUNNING)) {
mUpdatesRequested = mPrefs.getBoolean(Constants.RUNNING, false);
}
if(mUpdatesRequested){
ComponentName comp = new ComponentName(context.getPackageName(), BackgroundLocationService.class.getName());
ComponentName service = context.startService(new Intent().setComponent(comp));
if (null == service){
// something really wrong here
Log.e(TAG, "Could not start service " + comp.toString());
}
}
} else {
Log.e(TAG, "Received unexpected intent " + intent.toString());
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blackcj.locationtracker">
<!-- Used to start logging after re-boot -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".LocationLoggerServiceManager"
android:enabled="true"
android:exported="false"
android:label="LocationLoggerServiceManager">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".BackgroundLocationService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action
android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
</application>
</manifest>
@ritesh2014
Copy link

The service stops to track location if the user turns off and then again turns on the location from the phone. Ideally it should continue tracking if the location is again turned on. I am not able to figure out a fix for this. Can you pls help?
UPDATE - the service starts collecting date after 7-8 mins once the location is turned on the device...so it does not stops completely but definitely there is a significant lag

@aegis1980
Copy link

@ritesh2014
You need to add receivers to your manifest for GPS on/off (similar to the one added for BOOT_COMPLETED above). Look at S.O. question/answer here. Have not tried it but makes sense. Could also add similar for airplane mode and whatever else.

Incidentally, I wanted service to run continuously, even when phone (screen) off. Made following mods to BackgroundLocationService.java with wakelock:

public int onStartCommand (Intent intent, int flags, int startId)
{
    super.onStartCommand(intent, flags, startId);
    PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE); //*** added this
    mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); //*** added this
    mWakeLock.acquire(); //*** added this

    if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
        return START_STICKY;

    setUpLocationClientIfNeeded();
    if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress)
    {
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
        mInProgress = true;
        mLocationClient.connect();

        // When the location client is connected, set mock mode
        mLocationClient.setMockMode(true);
    }

    return START_STICKY;
}

and this:

@Override
public void onDestroy(){
    // Turn off the request flag
    mInProgress = false;
    if(servicesAvailable && mLocationClient != null) {
        mLocationClient.removeLocationUpdates(this);
        // Destroy the current location client
        mLocationClient = null;
    }
    // Display the connection status
    Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
    mWakeLock.release(); ///**** added this
    //appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
    super.onDestroy();  
}

Not sure how well this performs in terms of battery life yet - seems to be going okay on my GNex - but seems to keep locations commingt a bit smoother when screen off. Need to add android.permission.WAKE_LOCK permission to manifest.

@hegazy
Copy link

hegazy commented Dec 4, 2014

You should close the connection to Google Play Services on onDestroy()
mLocationClient.disconnect();

@shroffrushabh
Copy link

Perfect exactly what I was looking for :)

@tspshikari
Copy link

Is Internet connection required to use google playservices location api ?

@JimVanG
Copy link

JimVanG commented Jan 10, 2016

Wow great stuff, thanks a lot!

I know this is a pretty old Gist so here are some updates to the code:

  • Firstly, you're going to want to use the GoogleApiClient rather than the 'LocationClient'. So change that where needed.

    • You build the GoogleApiClient like this, using it is pretty much the same as the other class:
    protected synchronized void buildGoogleApiClient() {
        Log.i(TAG, "Building GoogleApiClient");
        this.mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }
  • Added some checks to onStartCommand to stop multiple WakeLocks from being retained as they were causing errors.

public int onStartCommand (Intent intent, int flags, int startId)
{
    super.onStartCommand(intent, flags, startId);

    PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);

    /*
    WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring.

    This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find.
    */
    if (this.mWakeLock == null) { //**Added this
        this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
    }

    if (!this.mWakeLock.isHeld()) { //**Added this
    this.mWakeLock.acquire();
    }

    if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
        return START_STICKY;

    setUpLocationClientIfNeeded();
    if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress)
    {
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
        mInProgress = true;
        mGoogleApiClient.connect();
    }

    return START_STICKY;
}
  • Change this line in onConnect:
        Intent intent = new Intent(this, LocationReceiver.class);
        PendingIntent pendingIntent = PendingIntent
                .getBroadcast(this, 54321, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            mLocationClient.requestLocationUpdates(mLocationRequest, locationIntent);  //** This line changes
  • To:
        Intent intent = new Intent(this, LocationReceiver.class);
        PendingIntent pendingIntent = PendingIntent
                .getBroadcast(this, 54321, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
                mLocationRequest, pendingIntent); // This is the changed line.
  • Here's my onDestroy:
    @Override
    public void onDestroy() {
        // Turn off the request flag
        this.mInProgress = false;

        if (this.servicesAvailable && this.mGoogleApiClient != null) {
            this.mGoogleApiClient.unregisterConnectionCallbacks(this);
            this.mGoogleApiClient.unregisterConnectionFailedListener(this);
            this.mGoogleApiClient.disconnect();
            // Destroy the current location client
            this.mGoogleApiClient = null;
        }
        // Display the connection status
        // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
        // Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();

        if (this.mWakeLock != null) {
            this.mWakeLock.release();
            this.mWakeLock = null;
        }

        super.onDestroy();
    }
  • Here's the updated LocationReceiver BroadcastReceiver:
public class LocationReceiver extends BroadcastReceiver {

    private String TAG = this.getClass().getSimpleName();

    private LocationResult mLocationResult;

    @Override
    public void onReceive(Context context, Intent intent) {
              // Need to check and grab the Intent's extras like so
        if(LocationResult.hasResult(intent)) {
            this.mLocationResult = LocationResult.extractResult(intent);
            Log.i(TAG, "Location Received: " + this.mLocationResult.toString());
        }

    }
}

Also, @tspshikari: No the Internet permission is not required to use the GooglePlayServices Location API, that was probably just some other permission that they had for their app. :)

@nadjasah
Copy link

Great stuff! 👍

@JimVanG, one question: why do you need a wake lock when the pending intent method handles location updates in background for you? If you set the LocationReceiver to inherit from a WakefulBroadcastReceiver, I think you can spare yourself the wake lock. (I am a beginner to Android so just thinking out loud, would appreciate any thoughts on this one!) :-)

@blackcj
Copy link
Author

blackcj commented Feb 2, 2016

Thank you for the updates @JimVanG. I've already put your WakeLock code to good use in my current project. I will update this gist to include those changes along with an update for Android 6.0 permissions in the near future. It's great to see that this old gist is still getting used.

@priithaamer
Copy link

This is very helpful 👍

It took me a moment to realize that LocationReceiver has to be registered in AndroidManifest.xml.

 <receiver android:name=".LocationReceiver" />

@henriquedesousa
Copy link

Waiting for the new version, it's a great piece of code.

Just for note, I had to change the LocationReceiver to an inner static class, and also add it as well as the service to the Manifest:

<receiver android:name=".service.BackgroundLocationService$LocationReceiver" />
<service android:name=".service.BackgroundLocationService" android:exported="false" />

@ayoola-solomon
Copy link

Awesome stuff... Just what I was looking for 👍 💯

@ticofab
Copy link

ticofab commented May 18, 2016

hey @blackcj news on an updated version of the gist? :)

@blackcj
Copy link
Author

blackcj commented Jun 23, 2016

The code has been updated with changes provided by @JimVanG and the latest support library. If targeting Android 23+ you will need to update to support the permission model changes.

@sudikrt
Copy link

sudikrt commented Jul 1, 2016

Sir, Can you please provide the complete source code please!?

@Paul776
Copy link

Paul776 commented Jul 26, 2016

I need to pass params to the receiver.

Intent intent = new Intent(this, LocationReceiver.class);
intent.putExtra(..)

In the LocationReceiver I do receive my Extra on the other hand LocationResult.hasResult always result false.

is there a work around for this?

@opcodewriter
Copy link

opcodewriter commented Jul 31, 2016

@Paul776 I changed from PendingIntent.FLAG_CANCEL_CURRENT to PendingIntent.FLAG_UPDATE_CURRENT

Edit: weird, this only works on a device with Android 5.1 not on a device with Android 4.3

Can someone help?

@opcodewriter
Copy link

why is Wake Lock required since background updates are sent by OS to the BroadcastReceiver by the PendingIntent?

@Paul776
Copy link

Paul776 commented Aug 3, 2016

Also I'm trying this code on Android 5 as well and when I kill the application in the task manager the server is killed and never comes back

@Paul776
Copy link

Paul776 commented Aug 3, 2016

If I remove the wake lock gibberish, in THAT case the service is restart once killed. Can someone explain what is this wakeup used for ?

@blackcj
Copy link
Author

blackcj commented Aug 8, 2016

@Paul776 It really depends on your use case. This code is intended for "always on" location tracking which will impact battery. Another solution would be to set up an AlarmManager to wake at specific intervals. The WakeLock is used to ensure background code execution isn't interrupted when the device goes to sleep. In my testing, the WakeLock is keeping the service alive after reboot and when force closing the app.

@anamikagit
Copy link

anamikagit commented Aug 30, 2016

@blackcj where is the Main Activity Sir

@goyalsk
Copy link

goyalsk commented Aug 31, 2016

Hi,
I am a newbee... I am trying to replace my current logic to get location by pendingIntent method. During my search, I came across your forum and really appreciated the gist but somehow, onLocationChanged is not getting fired. I am struggling to figure the missing link. Can you please help.....
I have included the definitions for both in manifest also.
My code is saved @
https://gist.github.com/goyalsk/324827993f96cd08a63a520991b34acc

@Paul776
Copy link

Paul776 commented Sep 3, 2016

@blackcj
This doesn't seems to work properly. Yes the service stay alive when killing the app. But when the device goes to sleep. I don't receive the location anymore

Moreover setting mGoogleApiClient = null; in the onConnectionSuspened cause a NPE here
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
mLocationRequest, this); // This is the changed line.

When on onConnectionSuspened is called, Android will start to reconnect by himself. when it succeed, onConnected is called again and here you have your NPE

One more thing. When the service is killed by Android because he decided it (:)) onDestroy won't be called thus the wakeLock won't e release (though Im not sure this is a problem because the service is dead anyway)

@goyalsk
Copy link

goyalsk commented Sep 7, 2016

Hi, I was able to resolve my issue.... I did the following:

  1. use WakefulBroadcastReceiver and hence did not require wakelocks in background service.
  2. Created a new intentService to receive location updates from LocationReceiver and do all relevant processing.
  3. Updated location receiver to send the location details to intentService.

Thanks for your help.

@stagga85
Copy link

stagga85 commented Nov 9, 2016

Can't this all just be done using a PendingIntent?

@recaldev
Copy link

recaldev commented Jan 24, 2017

Hello, in the onConnectionFailed there is a comments that says:

        /*
         * Google Play services can resolve some errors it detects.
         * If the error has a resolution, try sending an Intent to
         * start a Google Play services activity that can resolve
         * error.
         */

The problem is that in the Service i cannot solve this, i have this code in an activity right now:

@Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        if (mResolvingError) { // Already attempting to resolve an error.
            return;
        } else if (connectionResult.hasResolution()) {
            try {
                mResolvingError = true;
                connectionResult.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) { // There was an error with the resolution intent. Try again.
                mGoogleApiClient.connect();
            }
        } else { // Show dialog using GoogleApiAvailability.getErrorDialog()
            showErrorDialog(connectionResult.getErrorCode());
            mResolvingError = true;
        }
}

As you can see i need the onActivityResult method and other stuff from activity, if this callback is called in the service how can i launch an intent to solve this? If the GoogleApiClient object is on the service how can i can communicate that the problem was solved?

I'm having a bad time trying to implement this because this Service is exactly what i was needing and it works fine but what happen if the onConnectionFailed is called? I need to know the position of the client every few minutes.

@andrewclam1991
Copy link

Hi newbie here. How does the service communicate back to the calling activity with the completed work?

@pgomez-racowireless
Copy link

pgomez-racowireless commented Aug 1, 2017

Hi All,

I found this Gist very useful so I just wanted to thank you all for sharing.

also @andrewclam1991 I communicate back to the activity doing the following changes:

  1. on the BackgroundLocationService make it implement LocationListener which will make you override "onLocationChanged(Location location)" function
  2. from that function "onLocationChanged" you can send a broadcast like this: "sendBroadcast(Intent(ACTION_SEND_UI_UPDATE))"
  3. On your activity you can register for that event like this (code is in Kotlin but you get the idea):
    override fun onStart() { super.onStart() registerReceiver(mUpdateUIListener, BackgroundLocationService.intentFilter) } override fun onStop() { super.onStop() unregisterReceiver(mUpdateUIListener) } private val mUpdateUIListener = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { ACTION_SEND_UI_UPDATE -> { //Do some work here } } } }

Hope this is useful for someone

@FaizanMubasher
Copy link

Use this
GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) instead of this GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

@princearagones
Copy link

Hello there, how come when i implemented this, background service when i use stopService(i) // i = intent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment