0

Hello I'm currently trying to obtain the latitude and altitude values for my Android device using the GoogleApiClient. I've been following the guide here:

GoogleApiClient: Last Known Location Guide

I'm also trying to do this from my Service and not the Activity, here's a snippet of my code for reference:

public class AppService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private GoogleApiClient googleApiClient;

@Override
public IBinder onBind(Intent arg0) {
    return null;
}

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
    if (googleApiClient == null) {
        googleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }
    googleApiClient.connect();
    try {
        Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
        Log.d("location", String.valueOf(lastLocation.getLatitude()));
        Log.d("location", String.valueOf(lastLocation.getLongitude()));
    } catch (SecurityException e) {
        Log.e("Location error", "Location object is null.");
    }

    googleApiClient.disconnect();

    //Stop service once it finishes its task
    stopSelf();
    return Service.START_STICKY;
}

@Override
public void onConnected(@Nullable Bundle bundle) {

}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}
}

Every time I try to access the Location variable to obtain latitude and altitude I get a NullPointerException, any idea why?

Also want to include my AndroidManifest file just in case, I have the permissions needed as far as I know:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="app"
      android:versionCode="1"
      android:versionName="1.0" >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:label="@string/app_name" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </activity>
    <receiver
            android:name=".AutoStart"
            android:enabled="true" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        </intent-filter>
    </receiver>
    <service android:name=".AppService"/>
</application>
</manifest>
Tuco
  • 902
  • 3
  • 18
  • 33

1 Answers1

1

The call to googleApiClient.connect() is asynchronous according to the documentation:

public abstract void connect ()

Connects the client to Google Play services. This method returns immediately, and connects to the service in the background. If the connection is successful, onConnected(Bundle) is called and enqueued items are executed. On a failure, onConnectionFailed(ConnectionResult) is called.

If the client is already connected or connecting, this method does nothing.

Because of this, you should wait for the onConnected callback to be executed, and place your location retrieve code inside there.

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
  if (googleApiClient == null) {
     googleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
  }
  googleApiClient.connect();
  return Service.START_STICKY;
}

@Override
public void onConnected(@Nullable Bundle bundle) {
  try {
    Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
    Log.d("location", String.valueOf(lastLocation.getLatitude()));
    Log.d("location", String.valueOf(lastLocation.getLongitude()));
  } catch (SecurityException e) {
    Log.e("Location error", "Location object is null.");
  }

  googleApiClient.disconnect();
  stopSelf();
}
Robert Estivill
  • 12,369
  • 8
  • 43
  • 64
  • Oh I see, and what should I do if I need to use the latitude and altitude values in my service? After I obtain these values I need to use them in a thread I create inside the OnStartCommand method of my service: `Thread thread = new Thread(new Runnable(){ @Override public void run() { //Application logic where i need to use values } }); thread.start();` – Tuco Sep 26 '16 at 20:28
  • I posted the solution. You need to wait the google api client to be connected, before you can retrieve the location from it. Well you should start your thread whenever you actually have the location, not when you start your service. – Robert Estivill Sep 26 '16 at 20:30