2

I have an Android app with a Google Map and automatic location updates via Google Play Services' new location API.

Implemented just like this: https://developer.android.com/training/location/receive-location-updates.html

I'm specifically trying to receive GPS / accurate locations.

It works 100% perfectly and normally, GPS icon is on above, locations coming in every few seconds, no worries.

The odd problem seems to be that if you switch to Google Maps, wait a second, then switch back to my application, my app then gets exactly one more location update, and then stops receiving updates.

My app is properly stopping location updates onPause/onStop, and re-connecting and re-starting them onStart/onResume.

My debug Toasts show "Connected" after switching back from Google Maps, and show one more "Updated Location", then the updates stop. onDisconnected() is not getting called, and checks of mLocationClient.isConnected() report 'true'.

I have since added a hack work-around with a timer handler that runs every few seconds and if a location hasn't been found in the last 10 seconds, it calls stopPauseLocation() and checkStartLocation() below, which does fix the issue and locations start coming in again. Obviously this is an ugly hack and I'm not happy about it.

It seems to be like a bug, something conflicting between Google Maps and my own app, however, I can't for the life of me figure out a real solution.

Any ideas?

Here's the key code snippets:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Create the LocationRequest object
    mLocationRequest = LocationRequest.create();
    // Use high accuracy
    mLocationRequest.setPriority(
            LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set the update interval to 2 seconds
    mLocationRequest.setInterval(2000);
    // Set the fastest update interval to 1 second
    mLocationRequest.setFastestInterval(1000);
    /*
     * Create a new location client, using the enclosing class to
     * handle callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);

    mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
}

@Override
protected void onStart() {
    super.onStart();

    // Check our connection to play services
    checkStartLocation();
}

/*
 * Called when the Activity is no longer visible at all.
 * Stop updates and disconnect.
 */
@Override
protected void onStop() {
    stopPauseLocation();
}

/*
 * 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 dataBundle) {
    // Display the connection status
    Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
    mLocationClient.requestLocationUpdates(mLocationRequest, this);

    super.onStop();
}

private void stopPauseLocation()
{
    // If the client is connected
    if (mLocationClient.isConnected()) {
        /*
         * Remove location updates for a listener.
         * The current Activity is the listener, so
         * the argument is "this".
         */
        mLocationClient.removeLocationUpdates(this);
    }
    /*
     * After disconnect() is called, the client is
     * considered "dead".
     */
    mLocationClient.disconnect();
}

/**
 * Helper to check if we're connected to play, and try to connect if not
 */
protected void checkStartLocation() {
    if (!mLocationClient.isConnected())
    {
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationClient.connect();
    }
}

/*
 * 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 dataBundle) {
    // Display the connection status
    Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
    mLocationClient.requestLocationUpdates(mLocationRequest, this);
}

@Override
public void onDisconnected() {
    // Display the connection status
    Toast.makeText(this, "Disconnected.",Toast.LENGTH_SHORT).show();
}

/*
 * Called by Location Services if the attempt to connect to
 * Location Services fails.
 */
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Toast.makeText(this, "onConnectionFailed", Toast.LENGTH_SHORT).show();
}

 // 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 = "Updated Location: " +
            Double.toString(location.getLatitude()) + "," +
            Double.toString(location.getLongitude());
    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
4

1 回答 1

2

我发现的唯一方法是 hack,但这是我想出的最好的 hack 版本。

下面的代码将每 10 秒(然后逐渐增加 15 秒、20 秒、最多 30 秒)检查一次位置更新。如果没有收到任何位置,它会调用 removeLocationUpdates() 和 requestLocationUpdates(),这似乎解决了我的问题。

private Handler locationCheck = null;
// Track the time of the last location update
private long lastLocationUpdate = System.currentTimeMillis();
private long lastLocationWaitTime = 0;
// How long to wait until we reconnect (10 sec)
private long WAIT_LOCATION_AGE_START = 10000;
// Increments of how much longer to wait before next check
// Increments on every failure to give the system more time to recover
private long WAIT_LOCATION_AGE_INCREMENT = 5000;
// Max time to wait
private long MAX_WAIT_LOCATION_AGE = 30000;

Add to onCreate in your class:
locationCheck = new Handler();

Add to onResume/onStart:
lastLocationUpdate = System.currentTimeMillis();
lastLocationWaitTime = WAIT_LOCATION_AGE_START;
locationCheck.removeCallbacks(locationCheckRunnable);
locationCheck.postDelayed(locationCheckRunnable, 1000);

Add to onStop/onPause:
locationCheck.removeCallbacks(locationCheckRunnable);

private Runnable locationCheckRunnable = new Runnable() {
    @Override
    public void run() {
        if ((System.currentTimeMillis() - lastLocationUpdate) > lastLocationWaitTime)
        {
            // Verify our connection
            checkStartLocation();
            // Reset the timer
            lastLocationUpdate = System.currentTimeMillis();
            // On next check wait a bit longer
            lastLocationWaitTime += WAIT_LOCATION_AGE_INCREMENT;
            lastLocationWaitTime = Math.min(lastLocationWaitTime, MAX_WAIT_LOCATION_AGE);
            // Re-request location updates
            mLocationClient.removeLocationUpdates(MyParentClassName.this);
            mLocationClient.requestLocationUpdates(mLocationRequest, LocationSocialBaseScreen.this);
        }

        locationCheck.postDelayed(this, 1000);
    }
};

@Override
public void onLocationChanged(Location location) {
    lastLocationUpdate = System.currentTimeMillis();
}
于 2013-10-21T10:13:49.580 回答