Android requestLocationUpdates with GPS null

2020-04-21 09:25发布

问题:

private void getLocation(){
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    List<String> providers = locationManager.getAllProviders();
    for (String provider : providers) {
        Log.e("GPS_provider: ", provider);
    }
    Criteria criteria = new Criteria();
    bestProvider = locationManager.getBestProvider(criteria, false);
    Log.e("Best_provider: ", bestProvider);
    locationListener = new LocationListener() {
        public void onLocationChanged(Location location) {
            // Called when a new location is found by the network location provider.
            Log.e("Loc_changed", ""+ location.getLatitude() + location.getLongitude());
            mLocation = location;
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {}

        public void onProviderEnabled(String provider) {
            Log.e("Provider_enabled:", provider);
        }

        public void onProviderDisabled(String provider) {
            Log.e("Provider_disabled:", provider);

        }
    };
    // Register the listener with the Location Manager to receive location updates
    try {
        locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
        mLocation = locationManager.getLastKnownLocation(bestProvider);
        if (mLocation == null){
            mLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            Log.e("GPS network", "true");
        }
    } catch (SecurityException e){
        Log.e("GPS problem", "GPS problem "+e.getMessage());
    }
}

I'm trying to read position before doing an HTTP GET to retrieve my records:

private void loadBusinesses(){
    gpsMsg.setVisibility(View.INVISIBLE);
    getLocation();
    currentView = GEOVIEW;
    businessesList.nextUrl = "null";
    if (!businessesList.isEmpty()){
        Log.e("businessList ","not empty");
        businessesList.clear();
        notifyAdapter();
    }

    Double latitude;
    Double longitude;
    try{
        latitude = mLocation.getLatitude();
        longitude = mLocation.getLongitude();
    } catch (NullPointerException e){
        Log.e("GPS", "Location unavailable");
        gpsMsg.setVisibility(View.VISIBLE);
        swipeContainer.setRefreshing(false);
        return;
    }

}

Even if i check if GPS is turned on, i always get null when i try to use GPS position, and then it takes position from NETWORK. For this reason i tried to setup GPS setting to "only GPS", and i get NULL, so no position. I read all other posts but i keep taking null on GPS. I'm emulating on a real device with USB Debug.

Any idea?

回答1:

I believe you are interpreting wrong how the LocationManager works.

When you call locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener) you are just registering to receive location updates, which normally takes some time to occur (and may never occur, as CommonsWare pointed out). This call does not gives you right away an updated location, so, in the next line of code, when you call getLastKnownLocation(), it's normal behavior to receive null.

That said, I believe the best way to deal with your situation is this:

1 - First: check whether getLastKnownLocation() returns null or not (if the chosen LocationProvider has already a recent location from your app or even from another app, it will return it for you here. But beware: this location could be very outdated!).

2 - If getLastKnownLocation() returns null, then you will have no other option but to request a brand new location and wait for it to arrive, which will happen on the method onLocationChanged in the LocationListener. So, to do that you have two options: (a) call requestSingleUpdate(), which will return an updated location for you just one time, or (b) call requestLocationUpdates(), which will register the locationManager to receive periodical location updates (and will consume more battery).

3 - In both options, when you receive a location update, the method onLocationChanged in the LocationListener will be called and then you can call your loadBusinesses from this method, with the brand new location received.

Hope this is clear ;)

----- EDIT -----

You should also request location permissions on runtime, before calling requestSingleUpdate or requestLocationUpdates. To do that, use this snippet:

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    // If permission is not granted, request it from user. When user responds, your activity will call method "onRequestPermissionResult", which you should override
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
} else {
    locationManager.requestSingleUpdate(bestProvider, locationListener, null)
}

If the permission was not granted before, the user will be prompted to grant it (or not). So, you should also @Override the method onRequestPermissionResult in your activity, to check whether user granted the permission or not, and then respond properly. This is the method you should override:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // PERMISSION WAS GRANTED
            } else {
                // USER DID NOT GRANT PERMISSION
            }
            break;
    }
}


回答2:

The thing about getLastKnownLocation() is that if you change the location providers in the settings, restart your device, or turn location services on and off on your device, the last known location is cleared and will return null. On top of that, if a location point is returned, it could be so old that it may be irrelevant. The getLastKnownLocation() function should be used as a hint.

In regards to your comment saying that you get nothing when you use GPS indoors, but Google Maps still functions... Google Maps uses FusedLocationProviderApi, which uses both GPS and Network to give you the best location at that time. If you were to use GPS only on your device, and turn on Google Maps, you'll either see it give you a bad point (gray dot), or no point at all.

I would recommend you use Google's Fused Location provider for your location needs, as it will give you battery savings, reliable fallbacks in case you lose GPS, and has it's own last known location function that doesn't seem to be related to the LocationManager.



回答3:

getLastKnownLocation() frequently returns null. This is perfectly normal. You only use getLastKnownLocation():

  • as an optimization, to avoid having to wait for a location fix, or
  • if you can live without the location data

Otherwise, you need to postpone your HTTP GET request until you get a location given to you in onLocationChanged(). Bear in mind that you may never get a location fix.

The proper use of LocationManager is covered in the documentation.