Locating a user using Google Play Services

  • Tutorial
Good afternoon friends!

The question of determining the user's location on the maximum number of devices tormented me for about six months. It even came to the bicycles described here and here . The fact was that there were devices on which the location was not determined, for an unknown reason, but other applications worked quite well. Once again, delving into the code and rummaging through the vastness of the rumble in search of what I was missing and an implementation that I had not tried yet, I came across a fresh google manual article and, oh gods (!), It worked.

In this article I want to tell how I used this for my own purposes and give a simple example.
I want the source


The official example shows how to do all this in one activity, since it is important for them to show only the features, and I needed convenience, so I put everything in a separate class.

To get started, you need to initialize instances of the LocationClient and LocationRequest classes . The first is responsible for accessing the basic methods of the location API and Geofence, the second serves the LocationClient and is responsible for updates, i.e., callbacks are made through it. Using LocationRequest, as in the example below, you can set the update intervals, priority for positioning accuracy, and update intervals.

    private LocationRequest mLocationRequest;
    private LocationClient mLocationClient;    
    private LocationListenerGPServices(final Context context)
    {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setFastestInterval(FAST_INTERVAL_CEILING_IN_MILLISECONDS);
        mLocationClient = new LocationClient(context, this, this);
    }


Further, there are two options for the development of events: we can take the last known location or request a search for a new one.
In my case, I combine these two options, that is, at the beginning I get the last known location and, if it suits me, I use it, otherwise I request updates. In the code below, after calling the mLocationClient.connect () method, the onConnected (final Bundle bundle) method should work on the GooglePlayServicesClient.ConnectionCallbacks interface , which means that we were able to connect to the Google Play Services, i.e. Now we can sign up for a location update.


    public void enableMyLocation()
    {
        log("enableMyLocation");
        mLocation = null;
        mLocationClient.connect();
    }
    private boolean useCurrentLocation()
    {
        final Location location = mLocationClient.getLastLocation();
        if (System.currentTimeMillis() - location.getTime() < HALF_MINUTE)
        {
            log("useCurrentLocation");
            disableMyLocation();
            if (locationRunnable != null)
                locationRunnable.locationUpdate(location);
            return true;
        }
        return false;
    }


When we asked for a location to pass the time and not load the UI stream, I use AsynkTask as a timeout that works for a certain time, and upon completion it returns the location to the application and is unsubscribed from location updates.

    @Override
    public void onConnected(final Bundle bundle)
    {
        if (!useCurrentLocation())
        {
            mLocationClient.requestLocationUpdates(mLocationRequest, this);
            if (findLocation != null && !findLocation.isCancelled())
                findLocation.cancel(true);
            findLocation = new FindLocation();
            findLocation.execute();
        }
    }
    private Location endFind()
    {
        long sec = System.currentTimeMillis();
        while (this.mLocation == null && System.currentTimeMillis() - sec < TIME_OUT)
        {}
        return this.mLocation;
    }
   private class FindLocation extends AsyncTask
    {
        @Override
        protected Location doInBackground(final Void... params)
        {return endFind();}
        @Override
        protected void onPostExecute(final Location location)
        {
            if (locationRunnable != null)
                locationRunnable.locationUpdate(location);
            disableMyLocation();
        }
    }
    @Override
    public void disableMyLocation()
    {
       if (mLocationClient.isConnected())
            mLocationClient.removeLocationUpdates(this);
        mLocationClient.disconnect();
    }
    public interface LocationRunnable
    { public void locationUpdate(Location location);}


Actually how to use this example with github:
First you need to get an instance of the class, for myself I implemented singletone, since it is more suitable for my case
locationListener = LocationListenerGPServices.getInstance(this);

Then sign up for a location and do whatever you want with it.
locationListener.setLocationRunnable(new ILocationListener.LocationRunnable() {
            @Override
            public void locationUpdate(final Location location)
            {}});


Actually that's all I wanted to tell on this topic. Then I tried to tell briefly, and gave the minimum code for the text, in the sources on github I showed an example of how to find the user's location and sort the list of metro stations by distance to the user.

Thank you for your attention, I hope this helps someone and saves you from torment.

Also popular now: