4

I am wanting to implement location based functionality in my app. I have been reading a bit and I find my self a bit confused.

When googling for tutorial almost every result comes back with an example using Android Location API.

However when reading the android developer guidelines they state the following:

The Google Play services location APIs are preferred over the Android framework location APIs (android.location) as a way of adding location awareness to your app. If you are currently using the Android framework location APIs, you are strongly encouraged to switch to the Google Play services location APIs as soon as possible.

Android Docs

So this is telling me not to go for the simpler route of just implementing a Location Listener.

So my question is, what is the difference between the two? Why would I use one and not the other?

Where can I find a decent tutorial on how to safely and accurately access the Google play services location API properly.

I have tried this so far (as suggested on the Android site), However none of my Call Backs are being called.

public class LocationManager implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

private Context mContext;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;

public LocationManager(Context context) {
    mContext = context;
    //
    if (checkIfGooglePlayServicesAreAvailable()) {
        //Get Access to the google service api
        buildGoogleApiClient();
    } else {
        //Use Android Location Services
        //TODO:
    }
}

public Location getCoarseLocation() {
    if (mLastLocation != null) {
        return mLastLocation;
    } else return null;
}

private synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(mContext)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
}

private boolean checkIfGooglePlayServicesAreAvailable() {
    int errorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
    if (errorCode != ConnectionResult.SUCCESS) {
        GooglePlayServicesUtil.getErrorDialog(errorCode, (MainActivity) mContext, 0).show();
        return false;
    }
    return true;
}


@Override
public void onConnected(Bundle bundle) {
    Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (location != null) {
        mLastLocation = location;
        Toast.makeText(mContext, location.getLongitude() + " , " + location.getLatitude() + " : " + location.getAccuracy(), Toast.LENGTH_LONG).show();
    }
}

@Override
public void onConnectionSuspended(int i) {
    Toast.makeText(mContext, "suspended", Toast.LENGTH_LONG).show();
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Toast.makeText(mContext, connectionResult.toString(), Toast.LENGTH_LONG).show();
}
}

I then call my LocationManager From My Activity:

LocationManager locationManager = new LocationManager(this);
Location location = locationManager.getCoarseLocation();
//Use Location

I want to make a helper class which I can simply call from any activity or fragment. However when I run the following, the constructor executes successfully. However none of my breakpoints in the callbacks get hit. even after 1 or 2 minutes.

Zapnologica
  • 22,170
  • 44
  • 158
  • 253
  • From what I can see, judging by your code, you did not follow the Google guide like I remember I did... Where do you `requestLocationUpdates()`? – shkschneider Jan 08 '15 at 16:12
  • 2
    basically the google location API's are the same and the android ones except google's handles all the different location callbacks (GPS,Network,Wifi) so all you have to worry about is if you get a location or not – tyczj Jan 08 '15 at 16:15
  • @shkschneider I am simply getting last known location: https://developer.android.com/training/location/retrieve-current.html however I am not implementing it in an Activity, I am passing the activity reference to my class. – Zapnologica Jan 08 '15 at 16:17

2 Answers2

5

Google Play Services Api uses a callback method public void onConnected(Bundle bundle) which is called only when a connection is established. It is only then that the LocationServices.FusedLocationApi.getLastLocation(googleApiClient) method call will be able to return the correct Location.

You have constructed a helper class to obtain this location but you should understand that the connection is not established instantly. Therefore simply an async call to a helper class or it's method might return a null object as the connection might not have been made.

You could obtain the Location in the following ways.

1) Broadcast the location and receive it through a BroadcastReceiver to carry out the subsequent operations from within the public void onConnected(Bundle bundle). This worked for me.

private boolean flag = false;

@Override
public void onConnected(Bundle connectionHint) {
    location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
    if (location != null && !flag) {
        flag = true;
        Intent intent = new Intent(LOCATION_BROADCAST_ACTION);
        intent.putExtra(INTENT_EXTRA_LOCATION, location);
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        Log.i(TAG, "Sending Location Broadcast");
        Log.i(TAG, location.toString());
    } else if (location == null){
        Toast.makeText(mContext, R.string.no_location_detected, Toast.LENGTH_LONG).show();
        Log.e(TAG, "No Location Detected");
    }
}

2) Create a public Location object in the calling Activity or Fragment and update its value from within the public void onConnected(Bundle bundle) method.

@Override
public void onConnected(Bundle connectionHint) {
    location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
    if (location != null) {
        MyActivity.location = location; // update the Location object of you caller activity or fragment
        Log.i(TAG, "location updated");
    }
}

Moreover, you should connect to Google Play Services Location Api after building GoogleApiClient. Just add the method call mGoogleApiClient.connect() after your buildGoogleApiClient(); method call in your constructor. You don't need to check if Google Play Services are available or not.

You could also add the method call googleApiClient.connect(); in your implementation of public void onConnectionSuspended(int i).

Rahul Parida
  • 175
  • 1
  • 7
2

You need to call:

mGoogleApiClient.connect()

In addition to your question about the differences: the google play services framework provides you a "fused" location. With Android framework you should use GPS or Wif. You could specify a criteria but if you need the location user position, the google play services is the best choice. If you need a very precise position like GPS because for example your app is a navigator app, than it's better to use directly the GPS.

greywolf82
  • 21,813
  • 18
  • 54
  • 108
  • Where would it be best to call that? As I want the location? Or when instantiating my LocationManager Class? From your description I am defiantly looking for the play services one then. – Zapnologica Jan 08 '15 at 16:30
  • 1
    I think where you create the object. – greywolf82 Jan 08 '15 at 16:31
  • How long should `.connect()` take? because if I call. connect when I instantiate the object. I need it to be connected by the time I call `getCoarseLocation()` Is there a way I can block until it is connected? – Zapnologica Jan 08 '15 at 18:14
  • 1
    Sure you have to call blockingConnect() but you should call it on a background thread, don't call a blocking call on the UI thread – greywolf82 Jan 08 '15 at 18:23