- PVSM.RU - https://www.pvsm.ru -

Определение местоположения пользователя с помощью Сервисов Google Play

Добрый день, Друзья!

Вопрос определения местоположения пользователя на максимальном количестве девайсов мучил меня примерно пол года. Дело доходило даже до велосипедов, описанных тут [1] и тут [2]. Дело было в том, что находились устройства, на которых местоположение не определялось, по неизвестной причине, однако другие приложения работали вполне хорошо. Очередной раз, копаясь в коде и рыская в просторах гула в поисках того, что я упускаю, и реализации, которой я еще не опробовал, наткнулся на свеженькую статью-мануал [3] от google и, о боги(!), это заработало.

В данной статье я хочу рассказать, как я использовал это в своих целях и привести простой пример.

Хочу исходники

В официальном примере показывается как все это сделать в одном activity, так как им важно показать только возможности, а мне нужно было удобство, поэтому я все вынес в отдельный класс.

Для начала работы, необходимо инициализировать экземпляры классов LocationClient и LocationRequest. Первый отвечает за доступ к основным методам API определения местоположения и Geofence, второй обслуживает LocationClient и отвечает за обновления, т.е через него осуществляются колбэки(callbacks). С помощью LocationRequest, как в примере ниже, можно задавать интервалы обновления, приоритет для точности позиционирования и интервалы обновления.

    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);
    }

Далее есть два варианта развития событий: мы можем взять последнее известное местоположение или запросить поиск нового.
В моем случае, я комбинирую эти два варианта, т.е в начале я получаю последнее известное местоположение и, если оно меня устраивает, использую его, иначе я запрашиваю обновления. В коде ниже, после вызова метода mLocationClient.connect() должен сработать метод onConnected(final Bundle bundle) у интерфейса GooglePlayServicesClient.ConnectionCallbacks, который означает, что нам удалось подключиться к Сервисам Google Play, т.е. теперь мы можем подписаться на обновление местоположения.


    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;
    }


Когда мы запросили определение местоположения, чтобы скоротать как то время и не грузить UI — поток, я использую AsynkTask в качестве таймаута, который работает какое-то заданное время, и по завершению возвращает приложению найденное местоположение и отписывается от обновлений местоположения.

    @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<Void, Void, Location>
    {
        @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);}

Собственно как это использовать пример с github:
Для начала нужно получить экземпляр класса, для себя я реализовал singletone, так как он более подходит, для моего случая

locationListener = LocationListenerGPServices.getInstance(this);

Затем подписаться на получение местоположения и делать все, что вздумается с ним.

locationListener.setLocationRunnable(new ILocationListener.LocationRunnable() {
            @Override
            public void locationUpdate(final Location location)
            {}});

Собственно вот и все, что я хотел рассказать по данной теме. Тут я постарался рассказать в кратце, и привел минимум кода по тексту, в исходниках на github я показал на примере, как найти местоположение пользователя и отсортировать список станций метро по расстоянию до пользователя.

Спасибо за внимание, надеюсь кому-то это поможет и избавит от мучений.

Автор: andreich

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/android-development/41723

Ссылки в тексте:

[1] тут: http://hashcode.ru/questions/243575/java-locationlistener-%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0-%D0%B2-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B8-%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F

[2] тут: http://hashcode.ru/questions/243148/android-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B8%D1%82%D1%8C-%D0%BC%D0%B5%D1%81%D1%82%D0%BE%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F

[3] статью-мануал: https://developer.android.com/intl/ru/training/location/retrieve-current.html

[4] проект на github: https://github.com/rovkinmax/LocationWithGooglePlayServices

[5] Источник: http://habrahabr.ru/post/191290/