Search code examples
androidandroid-gps

cannot get location even gps are enabled


i have a function that uses multiple location provider to get latest known location info, but i found this is unstable (at least in my Xiaomi with android 7.1, i still don't know on another phone), here is my function :

private String getGPS() {
    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    List<String> providers = lm.getProviders(false);

    /* Loop over the array backwards, and if you get an accurate location, then break                 out the loop*/
    Location l = null;

    for (int i=providers.size()-1; i>=0; i--) {
        l = lm.getLastKnownLocation(providers.get(i));
        if (l != null) break;
    }

    String msg = "";
    if (l != null) {
        msg = l.getLatitude() + "|" + l.getLongitude();
    }
    return msg;
}

Solution

  • The method getLastKnownLocation() returns a valid location only if another app has requested it in recent past.

    You should do something like this:

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    
    //Avoid the for loop, in this way you can know where there's an issue, if there'll be
    
    Location l = lm.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
    
    if (l== null)
        l = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    
    if (l== null)
        l = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    

    Then, if all three are null, it means that no app has requested location before yours, so you have to do the request yourself: you can request "location updates", so you must implement a listener, if you want, you can insert it in your activity, in this way:

    class YourActivity extends Activity() implements LocationListener {
    
        private Location l;
        private LocationManager lm;
    
        @Override
        ... onCreate(...) {
    
            lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    
            l = lm.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
    
            if (l == null)
                l = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            if (l == null)
                l = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    
            if (l == null) { //If you need a real-time position, you should request updates even if the first location is not null
                //You don't need to use all three of these, check this answer for a complete explanation: https://stackoverflow.com/questions/6775257/android-location-providers-gps-or-network-provider 
    
                lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, 10F, this);
                lm.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 10 * 1000, 10F, this);
                lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10 * 1000, 10F, this); //This consumes a lot of battery
    
                //10 * 1000 is the delay (in millis) between two positions update
                //10F is the minimum distance (in meters) for which you'll have update
            }
        }
    
        @Override
        void onLocationChanged(Location location) {
            l = location;
        }
    
        private String getGPS() {
            String msg = "";
            if (l != null) {
                msg = l.getLatitude() + "|" + l.getLongitude();
            }
            return msg;
        }
    
        //To avoid crash, you must remove the updates in onDestroy():
        @Override
        void onDestroy() {
            lm.removeUpdates(this)
            super.onDestroy()
        }
    }
    

    Of course you have to insert in-app permission request for Android 6+