0

So there are many similar questions asked based on this, and I have also got a working solution. However, this seems to only work on my physical Android device. If I were to use it with the emulator, the method returns a null value and I don't know why. Many sources mention that there is a better alternative to the code that I am currently using but they don't mention what/how exactly. This is the code that I am using to get the current location of my device:

@SuppressWarnings("MissingPermission")
    private LatLng getCurrentLocation() {
        LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        String locationProvider = LocationManager.NETWORK_PROVIDER;
        assert locationManager != null;
        android.location.Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
        return new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
    }

I also don't like the fact that I have to suppress warnings. Sources that I have looked at include:

https://developer.android.com/training/location/retrieve-current.html#java

What is the simplest and most robust way to get the user's current location on Android?

The first one doesn't work, I get a null value. The second one looks overly complicated for a simple result that I am seeking.

1 Answers1

1

This code works just fine in one of my projects:

public class LocationManager {
        private static LocationManager requestManager;
        private FusedLocationProviderClient mLocationProviderClient;
        private Location mLocation;
        private Location mMyCurrentLocation;
        private locationSuccessListener mListener;

    public Location getLocation() {
        return mLocation;
    }

    public void setLocation(Location location) {
        mLocation = location;
    }

    private LocationManager(FusedLocationProviderClient fusedLocationProviderClient) {
        this.mLocationProviderClient = fusedLocationProviderClient;
    }

    public static LocationManager createInstance(FusedLocationProviderClient fusedLocationProviderClient) {
        if (requestManager != null) {
            return requestManager;
        } else {
            return requestManager = new LocationManager(fusedLocationProviderClient);
        }
    }

    public static LocationManager getInstance() {
        return requestManager;
    }

    public void setLocation(Activity activity) {
        mListener = (locationSuccessListener) activity;
        LocationCallback callback = new LocationCallback();
        LocationRequest locationRequest = new LocationRequest();
        Task<Void> r = mLocationProviderClient.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper());
        r.addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                mLocationProviderClient.getLastLocation().addOnSuccessListener(activity, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        mMyCurrentLocation = location;
                        mLocation = location;
                        if (location != null) {
                            mListener.onLocationReceived();
                            mLocationProviderClient.removeLocationUpdates(callback);
                        }
                    }
                });
            }
        });


    }

    public Location getMyCurrentLocation() {
        return mMyCurrentLocation;
    }


    public interface locationSuccessListener {
        void onLocationReceived();
    }

You need to do something like that:

public class PlacesActivity extends SingleFragmentActivity implements NavigationView.OnNavigationItemSelectedListener, LocationManager.locationSuccessListener

and then in your activity you will get this:

@Override
    public void onLocationReceived() {
         Location l = LocationManager.getInstance().getMyCurrentLocation();
             if (l==null){
                 Toast.makeText(this, "unable to get location", Toast.LENGTH_SHORT).show();
                 
             }
    }

to get permission you suppose to do something like this:

if (ContextCompat.checkSelfPermission(Objects.requireNonNull(getActivity()), Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    0);
            
Alex Rmcf
  • 804
  • 7
  • 14
  • Thanks, but is it necessary to have permissions in the setLocation method? Or is that just my IDE? Also, what exactly is that method doing? I have created an instance of this class, and passed a new fusedlocationprovider. Should I call the getMyCurrentLocation method where I need it directly or do something before this? I think I am getting a null value returned if I don't do anything before this – Shrimat Kapoor Aug 07 '20 at 21:44
  • I think I have to also call set location and pass the current activity. However, you say that my activity needs to implement that interface inside the class, how exactly do I go about that? What do I implement in the onLocationReceived method? – Shrimat Kapoor Aug 07 '20 at 22:01
  • What exactly is RequestManager in your onLocationReceived method? And also, do I need to create a location manager or do I just call that method and then create a Location field that stores the current location and then can be used else where? – Shrimat Kapoor Aug 08 '20 at 23:06
  • I'm still getting null values returned, even after calling setLocation, could you please give some more detail :( – Shrimat Kapoor Aug 08 '20 at 23:32
  • Also, to note, if you use getInstance on a class directly, won't the instance returned be null by default because it hasn't been initialised? – Shrimat Kapoor Aug 09 '20 at 10:29
  • As i said you have to createInstance() first in onCreate method of your Aplication class. If you don't know what is it - create class (for example MyApplication) and extend it from Application, and then call onCreate function, and then inside it call LocationManager.createInstace(new FusedLocationProvider). After that you can call LocationManager.getInstance from any class of your Application. – Alex Rmcf Aug 09 '20 at 16:52
  • I edited RequestManager to LocationManager, sorry my mistake – Alex Rmcf Aug 09 '20 at 17:08
  • But if you do it that way setLocation is never called – Shrimat Kapoor Aug 09 '20 at 20:28
  • Also I have tried calling that method, but the line r.addOnSuccessListener gets skipped so the current location remains null. I think this was the same problem I was facing when trying it with the first link that I shared which is the FusedLocationProvider – Shrimat Kapoor Aug 09 '20 at 20:33
  • If you have any other solutions do let me know! Or maybe I've missed something.. – Shrimat Kapoor Aug 09 '20 at 20:33
  • Ok, my friend. This code works just perfectly in my project, so it suppose to work same way in your. You call LocationManager.createInstance in your Application class. You implement interface LocationManager.locationSuccessListener to activity wich suppose to get location. Then in onCreate method of that activity you call LocationManager.getInstance(this). After that as soon as device will get location you will get call of overrided onLocationReceived() method in your activity. inside it write code: LocationManager.getInstance.getMyCurrentLocation() to get Location! – Alex Rmcf Aug 10 '20 at 18:21
  • Edit to my last comment - in onCreate method of your activity you call LocationManager.getInstance().setLocation(this), NOT LocationManaget.getInstance(this) – Alex Rmcf Aug 10 '20 at 20:56
  • I did exactly this, but the line r.addOnSuccessListener ... is getting skipped when I run LocationManager.getInstance().setLocation(this), so the current location in the LocationManager class remains null. Should I show you my code? – Shrimat Kapoor Aug 11 '20 at 06:14
  • Should I be using the return value of LocationManager.createInstance? – Shrimat Kapoor Aug 11 '20 at 06:15
  • you don't need return value. Line r.addOnSuccessListener suppose to be skipped, you just register success reciever there. did you get location permission for your app? – Alex Rmcf Aug 11 '20 at 09:55
  • Yes, I got the permissions. If that line is skipped mCurrentLocation will always be null? Is there a way to debug this :( – Shrimat Kapoor Aug 11 '20 at 19:35
  • So with the permissions I need to check twice once for Task r ... and mLocationProviderClient.getLastLocation ... Should I check for permissions at both places? – Shrimat Kapoor Aug 11 '20 at 19:52
  • to debug this you have to put stop point inside onSuccess method. Do you understand how Listeners work in Java? – Alex Rmcf Aug 12 '20 at 06:57
  • Ok so, after spending some time on this, the currentLocation does get updated however, not when I need it. So I need access to the location in onMapsReady, but the currentLocation variable is not updated until afterwards. Is there a way to execute this before? I want the current location so that the map zooms onto the location at startup. – Shrimat Kapoor Aug 13 '20 at 12:54
  • I finally got it! I was missing the LiveData observation :) – Shrimat Kapoor Aug 13 '20 at 13:07