Search code examples
androidgoogle-mapslocationgoogle-api-client

Get current user location or last known location


I realize this question has been asked many times before but I'm asking it now because the answers are quite old (compared to the new API).

I've used Location Manager before but I've found it very unreliable. For example in my app, using getLastKnownLocation and/or current location, it would instantly load with the camera on the user's current location. But say if I turned the location on my device right before I started my app, it wouldn't have the camera on the user's current location but rather somewhere near Nigera (default view, I believe).

Only if I used Google Maps app and pin pointed my location or if I waited some time, then my app would load with the user's location in the view (using moveCamera).

Sometimes it would work and sometimes it wouldn't. But I want to use Google Api Client, or perhaps something smoother, to retrieve the user's location.

I want to do it like this:

1.) If the user doesn't have their location on, prompt them to turn it on.

2.) After turning location on, start the Maps camera/view with the user's current location in the center.

3.) Finally, if the user decides to take off location or move from their location, do absolutely nothing.

I've read a lot of questions here but I can't find anything that could help me configure this functionality using Google Api Client or anything else. I've tried almost everything with Location Manager but I still can't get it to work smoothly. And out of frustration, I've deleted all my Location Manager code.

If you want to see what I had written down or tried, most of my sources came from this question (and related):

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

Thank you for taking the time to read this.


Solution

  • The following service is gracefully giving me location with accuracy and status of Location Service . This service is used before I login to the application, as application requires Location Service to be enabled.

    Based on this service input you can

    1. Prompt user to turn on Location
    2. Once location is received, map's can be initiated
    3. If location is disconnected, take care of the rest logic

    Important points to remember for location updates are that

    • Specify minimum distance change for receiving updates setSmallestDisplacement(API will get back data even if we stay in one location for a long time without moving)
    • Set FastestInterval to receive location updates
    • Set priority parameter setPriority according to your requirement

        public class AppLocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
                GoogleApiClient.OnConnectionFailedListener,
                LocationListener{
    
            private LocationRequest locationRequest;
            private GoogleApiClient googleApiClient;
            private Context appContext;
            private boolean currentlyProcessingLocation = false;
            private int mInterval=0;
            private final int CONNTIMEOUT=50000;
            private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    
        @Override
        public void onCreate() {
            super.onCreate();
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            appContext=getBaseContext();
            Toast.makeText(getBaseContext(), "Location Service Started", Toast.LENGTH_SHORT)
                    .show();
            if(intent != null){
                mInterval = intent.getIntExtra(Constants.REFRESHTIMETAG, 5);
                mIMEI = intent.getStringExtra(Constants.IMEITAG);
                Log.v(Constants.BLL_LOG, "AppLocationService onStartCommand , mInterval=" + mInterval + " | mIMEI=" + mIMEI);
            }
            if (!currentlyProcessingLocation) {
                currentlyProcessingLocation = true;
                startTracking();
            }
    
            return START_STICKY;
        }
    
        private void startTracking() {
            Log.v(Constants.BLL_LOG, "startTracking");
            if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
                Log.v(Constants.BLL_LOG, "ConnectionResult SUCCESS");
                googleApiClient = new GoogleApiClient.Builder(this)
                        .addApi(LocationServices.API)
                        .addConnectionCallbacks(this)
                        .addOnConnectionFailedListener(this)
                        .build();
    
                if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
                    googleApiClient.connect();
                    Log.v(Constants.BLL_LOG, "googleApiClient.connect()");
                }else{
                    Log.v(Constants.BLL_LOG, "NOT connected googleApiClient.connect()");
                    //
                    //INTIMATE UI WITH EITHER HANDLER OR RUNONUI THREAD
                    //
                }
            } else {
                Log.v(Constants.BLL_LOG, "unable to connect to google play services.");
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        public AppLocationService() {
        }
    
        @Override
        public void onConnected(Bundle bundle) {
            Log.v(Constants.BLL_LOG, "onConnected");
            locationRequest = LocationRequest.create();
            locationRequest.setInterval(mInterval * 1000); // milliseconds
            locationRequest.setFastestInterval(mInterval * 1000);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            locationRequest.setSmallestDisplacement(MIN_DISTANCE_CHANGE_FOR_UPDATES);//distance change
            int permissionCheck = ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION);
            if (permissionCheck!= PackageManager.PERMISSION_DENIED)
            {    LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);}
    
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(appContext, "Location Service got connected", Toast.LENGTH_SHORT)
                            .show();
                }
            });
        }
    
        @Override
        public void onConnectionSuspended(int i) {
            Log.v(Constants.BLL_LOG, "onConnectionSuspended");
            //INTIMATE UI ABOUT DISCONNECTION STATUS
        }
    
        @Override
        public void onLocationChanged(Location location) {
            Log.v(Constants.BLL_LOG, "onLocationChanged position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
            //if (location.getAccuracy() < 500.0f) 
            Log.v(Constants.BLL_LOG, "onLocationChanged position: location.getAccuracy()= "+location.getAccuracy());
    
            //DO YOUR BUSINESS LOGIC, FOR ME THE SAME WAS TO SEND TO SERVER
            sendLocationDataToWebsite(location);        
    
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Log.v(Constants.BLL_LOG, "onConnectionFailed");
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(appContext, "Location Service got disconnected temporarily", Toast.LENGTH_SHORT)
                            .show();
                }
            });
        }
    
        /**
         * Send details to server
         * @param location
         */
        void sendLocationDataToWebsite(Location location){
    
    
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (googleApiClient != null && googleApiClient.isConnected()) {
                googleApiClient.disconnect();
            }
            this.unregisterReceiver(this.batteryInfoReceiver);
        }
    }
    

    NOTE: This service needs to be still tested in updated version