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

от автора

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

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

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

ссылка на оригинал статьи http://habrahabr.ru/post/191290/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *