Как стать автором
Обновить

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

Время на прочтение3 мин
Количество просмотров42K
Добрый день, Друзья!

Вопрос определения местоположения пользователя на максимальном количестве девайсов мучил меня примерно полгода. Дело доходило даже до велосипедов, описанных тут и тут. Дело было в том, что находились устройства, на которых местоположение не определялось, по неизвестной причине, однако другие приложения работали вполне хорошо. Очередной раз, копаясь в коде и рыская в просторах гула в поисках того, что я упускаю, и реализации, которой я еще не опробовал, наткнулся на свеженькую статью-мануал от 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 я показал на примере, как найти местоположение пользователя и отсортировать список станций метро по расстоянию до пользователя.

Спасибо за внимание, надеюсь кому-то это поможет и избавит от мучений.
Теги:
Хабы:
Всего голосов 23: ↑18 и ↓5+13
Комментарии28

Публикации

Истории

Работа

Ближайшие события