6

It works on most devices except Galaxy Note 2. It connects to Google Client, but can't reach onLocationChanged() that implements LocationListener. Anyone has any idea what it causes and why only on this device?

@Override
public void onLocationChanged(Location location) {

    mLastLocation = location;

    if (mLastLocation != null) {
        lat = mLastLocation.getLatitude();
        lng = mLastLocation.getLongitude();

        Toast.makeText(getApplicationContext(), String.valueOf(lat) + "/" + String.valueOf(lng), Toast.LENGTH_LONG).show();

        serverUrl = "http://(my server)/offers?lat=" + String.valueOf(mLastLocation.getLatitude())
                            + "&lng=" + String.valueOf(mLastLocation.getLongitude()) + "&distance=1";
        // save
        makeTag(serverUrl);

        // after getting location data - unregister listener
                    LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mFusedLocationCallback);
        new GetBackgroundUpdate().execute();
    } else {
        // get data from server and update GridView
        new GetBackgroundUpdate().execute();
        Toast.makeText(getApplicationContext(), R.string.no_location_detected, Toast.LENGTH_LONG).show();

     }
/**
Location methods
*/
protected synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
}

/**
* Runs when a GoogleApiClient object successfully connects.
*/
@Override
public void onConnected(Bundle connectionHint) {
    // Provides a simple way of getting a device's location and is well suited for
    // applications that do not require a fine-grained location and that do not need location
    // updates. Gets the best and most recent location currently available, which may be null
    // in rare cases when a location is not available.
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(1000);
    mLocationRequest.setFastestInterval(500);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

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

}

@Override
public void onConnectionFailed(ConnectionResult result) {
    // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
    // onConnectionFailed.
    Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());

    if (mResolvingError) {
        // Already attempting to resolve an error.
        return;
    } else if (result.hasResolution()) {
        try {
            mResolvingError = true;
            result.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 GooglePlayServicesUtil.getErrorDialog()
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(String.valueOf(result.getErrorCode()))
                    .setCancelable(false)
                    .setNegativeButton("Ok", new DialogInterface.OnClickListener() {
                        public void onClick(final DialogInterface dialog, final int id) {
                            dialog.cancel();
                        }
                    });
        final AlertDialog alert = builder.create();
        alert.show();
        mResolvingError = true;
    }

    //new GetBackgroundUpdate().execute();
}

@Override
public void onConnectionSuspended(int cause) {
    // The connection to Google Play services was lost for some reason. We call connect() to
    // attempt to re-establish the connection.
    Log.i(TAG, "Connection suspended");
    mGoogleApiClient.connect();
}

@Override
protected void onStart() {
    super.onStart();
    mGoogleApiClient.connect();
}

@Override
protected void onStop() {
    super.onStop();
    if (mGoogleApiClient.isConnected()) {
        mGoogleApiClient.disconnect();
    }
}
haraman
  • 2,744
  • 2
  • 27
  • 50
jean d'arme
  • 4,033
  • 6
  • 35
  • 70

1 Answers1

5

Edit: From the line in your comment where the NullPointerException is happening, just ensure that mLastLocation is not null.

if (mLastLocation != null){
    address = server + String.valueOf(mLastLocation.getLatitude()) + "&lng=" + String.valueOf(mLastLocation.getLongitude()) + "&distance=" + distance;
} 

Another thing to note is that you should always ensure that mGoogleApiClient is not null and connected before using it.

if (mGoogleApiClient != null && mGoogleApiClient.isConnected()){
  //..... use mGoogleApiClient.....
}

See documentation here

You should also add a check to see if Google Play Services are available, as sometimes the version available on the device is below the version that you compile your app with. There is a dialog that you can show if that is the case.

Below is how to check if Google Play Services are available.

private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        }
    }

Note that getLastLocation() has a high tendency to return null, so a good approach would be to register a location listener if you get a null value from the first call to getLastLocation().
See this post: LocationClient getLastLocation() return null

Here is a guide for how to register a LocationListener:

Creating a listener:

LocationCallback mFusedLocationCallback = new LocationCallback();

Class definition:

private class LocationCallback implements LocationListener {

        public LocationCallback() {

        }

        @Override
        public void onLocationChanged(Location location) {

                 mLastLocation = location;
                 lat = String.valueOf(mLastLocation.getLatitude());
                 lng = String.valueOf(mLastLocation.getLongitude());


             }
    };

Then just register the LocationListener :

  mLocationRequest = new LocationRequest();
  mLocationRequest.setInterval(minTime);
  mLocationRequest.setFastestInterval(fastestTime);
  mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
  mLocationRequest.setSmallestDisplacement(distanceThreshold);

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

Edit: You should wait for the API to be connected before you register for location callbacks, it should be something like this:

/**
 * Runs when a GoogleApiClient object successfully connects.
 */
@Override
public void onConnected(Bundle connectionHint) {
    // Provides a simple way of getting a device's location and is well suited for
    // applications that do not require a fine-grained location and that do not need location
    // updates. Gets the best and most recent location currently available, which may be null
    // in rare cases when a location is not available.
    mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (mLastLocation != null) {
        lat = String.valueOf(mLastLocation.getLatitude());
        lng = String.valueOf(mLastLocation.getLongitude());
    } else {
        Toast.makeText(this, R.string.no_location_detected, Toast.LENGTH_LONG).show();
    }


     mLocationRequest = new LocationRequest();
     mLocationRequest.setInterval(1000);
     mLocationRequest.setFastestInterval(500);
     mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

     LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mFusedLocationCallback);
}

Documentation: for requestLocationUpdates.... and LocationRequest.

One last thing, make sure that you have this in your AndroidManifest.xml inside the application tag:

  <meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />
Community
  • 1
  • 1
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • Should I use then if(mGoogleApiClient != null && mGoogleApiClient.isConnected() && mLastLocation != null) ? It would check everything at once – jean d'arme May 05 '15 at 16:10
  • @jeand'arme It just depends on what you are doing. You would not want to check all three at once before this line: `mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);` Note that `getLastLocation()` has a high tendency to return null, so a better approach would be to register a location listener if you get a null value. See this post: http://stackoverflow.com/questions/16830047/locationclient-getlastlocation-return-null – Daniel Nugent May 05 '15 at 17:01
  • I will try using location listener because my app is fully location-dependent. – jean d'arme May 05 '15 at 18:26
  • @jeand'arme I just updated the answer with a guide to set up a LocationListener, take a look. – Daniel Nugent May 05 '15 at 18:42
  • Ok, I registered LocationListener in onConnected() and address that is based on mLocation is done in Callback and so far it works. If it won't crash on tests I will accept that answer since it helped me a lot :) – jean d'arme May 06 '15 at 12:58
  • Yes, thank You. Thank god Google Location Api has this interface with onConnected() :) Cheers, man! – jean d'arme May 07 '15 at 18:44
  • Ok, those Samsung phones are really up to something: they don't want to read location... Are they so modified in system terms that they just are different to use? Should I update this question or make a new one witch applied changes (since LogCat is not providing errors)? – jean d'arme May 10 '15 at 11:35
  • @jeand'arme It works fine for me on my Samsung S4. Do you have the latest version of Google Play Services on your Samsung devices? – Daniel Nugent May 10 '15 at 16:05
  • @jeand'arme Also, make sure that the GoogleLocationAPI is connected before you call `requestLocationUpdates()` in order to register for location callbacks. You can use the `onConnected()` callback in order to do that. I just edited the answer, take a look at the edit at the bottom. – Daniel Nugent May 10 '15 at 17:17
  • I tested it on Galaxy Note 2 emulator (provided by Genymotion) and it works great. I sent my app to my brother who got problems with it (he has Note 2) and I hope it will eventually be good now because otherwise I don't know what else could be the problem. One question: if I don't use fragments should I use "maintain state while resolving error" from this link https://developer.android.com/google/auth/api-client.html ? Thanks in advance, as always You deliver great help, Daniel :) – jean d'arme May 10 '15 at 19:25
  • 1
    @jeand'arme Make sure that your brother has an updated version of Google Play Services. He should get a prompt to upgrade from the `getErrorDialog()` call if he needs to upgrade. Not sure about the maintain state thing, I'll check that out later when I have time. – Daniel Nugent May 10 '15 at 19:30
  • Just went through everything we could on Skype. So, he has the latest Google Play Services. He still couldn't get his location - even wth GPS turned on. I'm looking for a solution how to get coarse location if fine location fails. Maybe that could be a workaround since it could happen to other users as well. I have updated question with recent code, maybe You'd like to take a look. Every method related to location is there. – jean d'arme May 11 '15 at 18:25
  • I found something interesting on my brother phone now. To do thing based on location there is `(mGoogleApiClient != null && mGoogleApiClient.isConnected())` if statement. Interestingly, it can't locate itself, but apparently `GoogleApiClient` is not null and GoogleClientApi `isConnected` so now it's even more confusing because he can do things that normally shouldn't work (in that case location is defaulted to lat = 0 and lon = 0). How on earth it can be connected and yet not locate itself? #confused – jean d'arme May 12 '15 at 12:05
  • @jeand'arme Sorry, just getting around to looking at this now. I just looked at your updated code, and it looks good to me. Whatever the problem is, I don't think it's your code. – Daniel Nugent May 14 '15 at 15:41
  • Are there any workarounds like `if location is not obtained then get location through android.location.Location` ? I know this library is going to be deprecated, but could be this a reliable solution? – jean d'arme May 14 '15 at 15:47
  • @jeand'arme can you also show where `mFusedLocationCallback` is defined? The `onLocationChanged()` callback should be defined in this object. – Daniel Nugent May 14 '15 at 15:57
  • sure, it's defined before `onCreate()` and it's like this: `private LocationCallback mFusedLocationCallback = new LocationCallback();` which is made as You described (class with LocationListener interface and empty constructor) – jean d'arme May 14 '15 at 16:00
  • @jeand'arme Ok, just wanted to rule that out as the problem. Does it get into the `onLocationChanged()` callback on your brother's device? – Daniel Nugent May 14 '15 at 16:03
  • That will take me 2-3 hours since he's working right now, but as soon as I will get feedback from him - I will notify here. – jean d'arme May 14 '15 at 16:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77825/discussion-between-daniel-nugent-and-jean-darme). – Daniel Nugent May 14 '15 at 16:16
  • @jeand'arme can you post your full Activity class to a gist on gist.github.com? I can run it on my Samsung S4 and see if I can find any issues. – Daniel Nugent May 14 '15 at 16:22
  • @jeand'arme One more thing, can you add your build.gradle file and AndroidManifest.xml file to the question? – Daniel Nugent May 14 '15 at 18:04
  • I sent it to You through mail :) – jean d'arme May 14 '15 at 18:12
  • @jeand'arme I just updated the answer, add the `meta-data` tag for gms version, it might be the cause of things not working on your brother's device! – Daniel Nugent May 14 '15 at 18:34
  • Okay, I got feedback from him. It doesn't reach onLocationChanged(), so it may be the problem here. – jean d'arme May 15 '15 at 11:05
  • 1
    @jeand'arme Yes, that would definitely be the problem. The question now is what is the root cause of the problem that is preventing it from working correctly! – Daniel Nugent May 15 '15 at 15:03