|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Interfaces. Classes ⇐ ПредыдущаяСтр 2 из 2 Interfaces
Classes
Простой пример с использованием api android. location из одного класса.
import android. content. Context; import android. location. Location; import android. location. LocationListener; import android. location. LocationManager; import android. os. Bundle;
class MyLocationListener implements LocationListener {
static Location imHere; // в этой статической переменной будет всегда доступна самая последняя информация о местоположении пользователя.
public static void SetUpLocationListener(Context context) // это нужно запустить в самом начале работы программы { LocationManager locationManager = (LocationManager) context. getSystemService(Context. LOCATION_SERVICE);
LocationListener locationListener = new MyLocationListener();
locationManager. requestLocationUpdates( LocationManager. GPS_PROVIDER, 5000, 10, locationListener); // здесь можно указать другие более подходящие вам параметры
imHere = locationManager. getLastKnownLocation(LocationManager. GPS_PROVIDER); }
@Override public void onLocationChanged(Location loc) { imHere = loc; } @Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {} }
Класс разделен на 3 части: 1) imHere — переменная типа Location, в которой будет всегда доступна самая последняя информация о местоположении пользователя. 2) функция SetUpLocationListener — в любом случае нам нужна будет начальная установка для того, чтобы система начала сама без нашего участия выполнять обновление переменной imHere. 3) все остальные обязательные части LocationListener, которые можно переделать по собственному желанию.
Итак, как это работает?
1) создаем класс MyLocationListener 2) копируем в него код написанный выше 3) в основной функции (например MainActivity) ближе к началу запускаем:
MyLocationListener. SetUpLocationListener(this);
или для любителей потоков final Context mainContext = this; new Thread(new Runnable() { @Override public void run() { MyLocationListener. SetUpLocationListener(mainContext); } }). start();
4) теперь у нас всегда и в любой части нашего проекта есть переменная MyLocationListener. imHere типа Location, в которой хранится самое последнее местоположение пользователя и множество дополнительной информации, как например скорость или точность определения местоположения.
(! ) Не забудьте: в зависимости от выбранного провайдера нужно добавить в манифест соответствующее разрешение. Например используемый выше GPS_PROVIDER требует добавления следующей строчки в манифест:
< uses-permission android: name=" android. permission. ACCESS_FINE_LOCATION" />
2. Использование fused location provider
Возникла необходимость в более совершенных API. Но если бы они были добавлены в стандартную библиотеку, то в лучшем случае прошла бы пара лет, прежде чем все разработчики смогли использовать их. И это было неприятно, потому что у ОС было все необходимое для улучшенных API: GPS, приближенное позиционирование и т. д. К счастью, стандартная библиотека не единственный способ использования кода. Кроме стандартной библиотеки, Google предоставляет Play Services — набор стандартных сервисных функций, устанавливаемых вместе с приложением магазина Google Play. Для решения проблемы позиционирования компания Google опубликовала в Play Services новую версию сервиса позиционирования Fused Location Provider. Так как эти библиотеки существуют в другом приложении, это приложение должно быть установлено в системе. Это означает, что приложение может использоваться только на устройствах с установленным и обновленным приложением Play Store. Также это почти наверняка означает, что приложение будет распространяться через Play Store. Если же ваше приложение недоступно через Play Store, значит, вам не повезло и стоит подыскать другой API. Если вы будете тестировать приложение этой части лекции на физическом устройстве, убедитесь в том, что на нем установлено обновленное приложение Play Store.
Плюсами решения на основе Fused Location Provider является то, что вам не надо самому подыскивать наиболее точный источник координат, он сделает это за вас. Если запускать его с критериями для определения наиболее точного местоположения, то он будет работать по следующему принципу: 1) Если GPS доступен и включен, то выбирается GPS_PROVIDER в качестве источника. 2) Если GPS недоступен, то выбирается NETWORK_PROVIDER. В данном случаи координаты определяются при помощи вышек сотовой связи и WIFI. 3) Если не того не другого нет, то используется PASSIVE_PROVIDER. Тут система пытается использовать любой способ получить хоть какое-то местоположение в том числе и при использовании акселерометра. Этот провайдер наименее точный.
Полную информацию о классах и методах данного api читайте здесь. Ссылка рабочая. Не забывайте использовать впн для доступа к сервисам google для санкционных регионов.
Итак класс работы с этим api:
class LocationDeviceInteractor(activity: Activity) {
private val provider = LocationServices. getFusedLocationProviderClient(activity) private val settingDispatcher = LocationSettingDispatcher(activity)
private val lastLocationMaybe = Maybe. create< Location> { emitter -> try { provider. lastLocation. apply { addOnSuccessListener { location -> if (location! = null) emitter. onSuccess(location) emitter. onComplete() } addOnFailureListener { emitter. onError(it) } } } catch (e: Exception) { emitter. onError(e) } }
private class UpdateLocationMaybeSubscribe( private val provider: FusedLocationProviderClient): MaybeOnSubscribe< Location> {
private val locationGPSRequest = LocationRequest(). apply { numUpdates = 1 interval = 10000 fastestInterval = 5000 priority = LocationRequest. PRIORITY_HIGH_ACCURACY } override fun subscribe(emitter: MaybeEmitter< Location> ) { val callback = object: LocationCallback() { override fun onLocationResult(locationResult: LocationResult? ) { val location = locationResult?. locations?. find { location -> location! = null } if (location! = null) { removeLocationUpdates(this) emitter. onSuccess(location) } emitter. onComplete() } } provider. requestLocationUpdates(locationGPSRequest, callback, null) emitter. setDisposable(Disposables. fromRunnable { removeLocationUpdates(callback) }) } private fun removeLocationUpdates(callback: LocationCallback) { provider. removeLocationUpdates(callback) } } fun onActivityResult(requestCode: Int, resultCode: Int) { settingDispatcher. onActivityResult(requestCode, resultCode) } fun getLocation(): Maybe< Location> { return lastLocationMaybe . switchIfEmpty(settingDispatcher . asMaybe() . flatMap { allow -> if (allow) lastLocationMaybe. switchIfEmpty( Maybe. create(UpdateLocationMaybeSubscribe(provider))) else Maybe. create(UpdateLocationMaybeSubscribe(provider)) }) } }
в методе getLocation() с lastLocationMaybe мы может быть получим последнее известное положение и если оно пустое, то идет проверка на настройки аппарата, если все необходимые разрешения получены или уже были то мы пытаемся еще раз получить последнее положение и в случае его отсутствия остается последняя возможность запросить обновление местоположения. Лучше установить настройки поиска по всем источникам. В mainactivity прописывается вызов методов класса так:
private lateinit var locationDeviceInteractor: LocationDeviceInteractor private var disposable: Disposable? = null ... // место где мы хотим получить местоположение устройства locationDeviceInteractor = LocationDeviceInteractor(this) disposable = locationDeviceInteractor . getLocation() . subscribe({ Log. e(it. latitude. toString(), it. longitude. toString())}) ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent? ) { super. onActivityResult(requestCode, resultCode, data) locationDeviceInteractor. onActivityResult(requestCode, resultCode) } override fun onDestroy() { super. onDestroy() disposable?. dispose() ... }
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|