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