Search code examples
javaandroidlocationon-location-changed

onLocationChanged not called in Android 6.0 API 23


I'm trying to get the current location using this code and it works when launching the app and when bringing it to the foreground. The toasts show up in both cases, but otherwise they don't. Can anybody tell me where I messed up?

public class LocationFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener, LocationListener {

double oldLon,oldLat;

private static final String TAG = MainActivity.class.getSimpleName();        // LogCat tag
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private static final int MY_PERMISSIONS_REQUEST_FINE_LOCATION = 100;
private Location mLastLocation;
private GoogleApiClient mGoogleApiClient; 
private FusedLocationProviderClient mFusedLocationClient;

private LocationRequest mLocationRequest;

// Location updates intervals in sec
private static int UPDATE_INTERVAL = 10000; // 10 sec
private static int FATEST_INTERVAL = 5000; // 5 sec


@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);

    // First we need to check availability of play services
    if (checkPlayServices()) {

        buildGoogleApiClient();
        createLocationRequest();
    }

}

@Override
public void onDetach() {
    mCallback = null; // => avoid leaking
    super.onDetach();
}


public interface InterfaceTextClicked {
    public void sendText(String text);
}


private boolean checkPermission(){

    if(ActivityCompat.checkSelfPermission(getContext(),
            ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
        System.out.println("We have been granted.");
        return true;}
    else return false;
}

private void requestPermission(){
    ActivityCompat.requestPermissions(getActivity(),new String[]
            {ACCESS_FINE_LOCATION},MY_PERMISSIONS_REQUEST_FINE_LOCATION);
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_FINE_LOCATION: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay!
                System.out.println("Permission Granted!");

            } else {

                // permission denied, boo!
                System.out.println("Permission Denied!");

                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                    if(shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)){
                        new AlertDialog.Builder(getActivity())
                                .setMessage("Permission needed to access your location.")
                                .setPositiveButton("OK", new DialogInterface.OnClickListener(){
                                    @Override
                                    public void onClick(DialogInterface dialog,int which){
                                        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                                            requestPermissions(new String[]{ACCESS_FINE_LOCATION},
                                                    MY_PERMISSIONS_REQUEST_FINE_LOCATION);
                                        }
                                    }
                                })
                                .setNegativeButton("Cancel", null)
                                .create()
                                .show();
                        return;
                    }
                }
            }
            // return;
        }
       }
}

private void displayLocation(){

    System.out.println("Inside displayLocation");

    requestPermission();

    if(checkPermission()){
        mLastLocation = LocationServices.FusedLocationApi
                .getLastLocation(mGoogleApiClient);
    }

    if (mLastLocation != null) {
        double latitude = mLastLocation.getLatitude();
        double longitude = mLastLocation.getLongitude();

        System.out.println("Location1: "+latitude+" "+longitude);
        if(Double.compare(oldLat,latitude)==0 || Double.compare(oldLon,longitude)==0){
            Toast.makeText(getContext(), "Location didn't change! "+latitude+ " "+ longitude,
                    Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(getContext(), "Location changed! NEW: "+latitude+ " "+ longitude+" OLD: "+oldLat+ " "+oldLon,
                    Toast.LENGTH_LONG).show();
        }

       // mCallback.sendText(latitude+" "+longitude);

        oldLon = longitude;
        oldLat = latitude;

    } else {
        System.out.println("Couldn't get coordinates");
        if(mGoogleApiClient.isConnected()){
            System.out.println("Client connected");
        }else{
            System.out.println("Client NOT connected");
        }
    }
}

/**
 * Creating google api client object
 * */
protected synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(getContext())
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API).build();

}

/**
 * Method to verify google play services on the device
 * */
private boolean checkPlayServices() {
    GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
    int resultCode = googleAPI.isGooglePlayServicesAvailable(getContext());
    if (resultCode != ConnectionResult.SUCCESS) {
        if(googleAPI.isUserResolvableError(resultCode)){
            googleAPI.getErrorDialog(getActivity(),resultCode,
                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
        } else {
            Toast.makeText(getContext(),
                    "This device is not supported.", Toast.LENGTH_LONG)
                    .show();
            getActivity().finish();
        }
        return false;
    }
    return true;
}

@Override
public void onStart() {
    super.onStart();
    if (mGoogleApiClient != null) {
        mGoogleApiClient.connect();
    }
}

@Override
public void onResume() {
    super.onResume();
    if (mGoogleApiClient != null && !mGoogleApiClient.isConnected()) {
        mGoogleApiClient.connect();
    }
    checkPlayServices();
}


@Override
public void onStop() {
    super.onStop();
    if (mGoogleApiClient.isConnected()) {
        mGoogleApiClient.disconnect();
    }
}

/**
 * Creating location request object
 * */
protected void createLocationRequest() {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setInterval(UPDATE_INTERVAL);
    mLocationRequest.setFastestInterval(FATEST_INTERVAL);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);    }

/**
 * Starting the location updates
 * */
protected void startLocationUpdates() {

    System.out.println("Inside startLocationUpdates");
    requestPermission();
    if(checkPermission()){

        if ((mGoogleApiClient != null) && (mGoogleApiClient.isConnected())){

            LocationServices.FusedLocationApi.requestLocationUpdates(
                    mGoogleApiClient, mLocationRequest, this);

        }
    }
}


/**
 * Google api callback methods
 */
@Override
public void onConnectionFailed(ConnectionResult result) {
    Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
            + result.getErrorCode());

}

@Override
public void onConnected(Bundle arg0){

        startLocationUpdates();
        // Once connected with google api, get the location
        displayLocation();

}

@Override
public void onConnectionSuspended(int arg0) {
    mGoogleApiClient.connect();
}

@Override
public void onPause() {
    super.onPause();
    stopLocationUpdates();
}



/**
 * Stopping location updates
 */
protected void stopLocationUpdates() {
    if ((mGoogleApiClient != null) && (mGoogleApiClient.isConnected())) {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                mGoogleApiClient, this);
    }
}


@Override
public void onLocationChanged(Location location) {
    // Assign the new location
    mLastLocation = location;

    Toast.makeText(getContext(), "******Location changed!",
            Toast.LENGTH_SHORT).show();

    // Displaying the new location on UI
    displayLocation();

}

}

Sorry to put so much code up there, I thought my mistake could be anywhere so didn't want to cut out anything.

The Log shows the following:

10-14 01:10:27.408 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Inside startLocationUpdates
10-14 01:10:27.536 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: We have been granted.
10-14 01:10:27.610 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Inside displayLocation
10-14 01:10:27.617 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: We have been granted.
10-14 01:10:27.641 14485-14485/com.android.wy.parkingauthoritytickingsystem I/System.out: Location1: 40.4868602 -74.4388156

Solution

  • I don't see anything obviously wrong with your code, though it is making its API calls through the deprecated versions of the location APIs rather than the new FusedLocationProviderClient interface.

    While you declare a new-style FusedLocationProviderClient:

    private FusedLocationProviderClient mFusedLocationClient;
    

    you never initialize it or use it at runtime; rather you call through FusedLocationApi (the old method):

    LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
    

    You might try using the new API, which has a slightly more robust interface, to shed some light on your problem. You can get the new API interface with:

    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    

    Then you'll just need to tweak your class to add an onLocationAvailability callback as per the documentation before attaching your listener:

     mFusedLocationClient.requestLocationUpdates(mLocationRequest,
                mLocationCallback,
                null /* Looper */);