Android - лучший способ реализовать LocationListener для нескольких действий
Я давно застрял в этой проблеме. Я работаю над приложением, которое использует местоположение довольно широко в нескольких разных действиях. В каждом примере, который я нашел, в каждом мероприятии используется отдельный элемент LocationListener. Это невозможно в моей ситуации.
Мне интересно, какой самый эффективный способ отслеживать местоположение пользователя в нескольких действиях. Прямо сейчас я создал службу, которая реализует LocationListener и использует широковещательную рассылку для обновления статических лат и длинных полей в базовом классе Activity. Это означает, что служба всегда работает, что не идеально. Но если я выключу службу и перезапустим ее только тогда, когда она мне понадобится, потребуется время, чтобы получить хорошее место. Мне нужны данные о местоположении в Activity onCreate(). То же самое, если я попытаюсь реализовать его в базовом классе активности. Если я постоянно регистрирую слушателя в onResume/onCreate и не регистрирую его в onPause(), для начала получения обновлений требуется слишком много времени. Я также попытался создать службу, с которой я мог бы привязываться, поэтому она запускается только тогда, когда мне нужно место. Но у меня такая же проблема, требуется слишком много времени, чтобы привязываться к службе и начинать получать обновления.
Сервис, который я использую сейчас, работает, но из всего, что я читал, я не должен использовать постоянно действующий сервис для подобных вещей. Но весь смысл приложения - предоставить релевантные данные на основе текущего местоположения пользователя. Поэтому у меня есть служба, которая работает только в фоновом режиме и периодически обновляет ее. Одна из основных проблем, которая заставила меня пересмотреть дизайн на этом этапе, заключается в том, что я недавно обнаружил, что onProviderEnabled() не вызывается, если пользователь запускает приложение без включенного GPS и затем впоследствии его разрешает. В этом случае приложение не может распознать, что GPS включен, поэтому он может начать прослушивание обновлений.
Я думал, что я понял LocationManager и LocationListener, глядя на примеры, но я не могу применить его к этой ситуации, когда мне нужны данные о местоположении в нескольких действиях. Любая помощь или совет будут очень признательны.
Ответы
Ответ 1
То, как я обычно применяю это требование, - это использование связанной службы, например, в Пример локальной службы в документации SDK, Очевидно, что вы знакомы с преимуществом Сервиса, позволяющим создавать только код местоположения только один раз.
Доступ к службе через привязки позволяет Службе запускаться и останавливаться, поэтому он не работает, когда ваше приложение не находится на переднем плане (оно умрет, как только больше никаких действий не будет связано). Ключ, IMO, чтобы это хорошо работало, - это BIND-сервис в onStart()
и UNBIND в onStop()
, потому что эти два вызова перекрываются при переходе от одного действия к другому (вторая активность начинается до первой остановки). Это заставляет Службу умирать при перемещении внутри приложения и только позволяет службе умереть, когда все приложение (или, по крайней мере, любая часть, заинтересованная в местоположении) выходит из переднего плана.
С помощью Bindings вам не нужно передавать данные местоположения в широковещательном режиме, потому что Activity может вызывать методы непосредственно на службе, чтобы получить последнее местоположение. Тем не менее, широковещательная передача по-прежнему будет выгодна как способ указания WHEN, что новое обновление доступно... но это просто станет уведомляющим для прослушивающей активности вызовом метода getLocation()
в службе.
Мои $0,02. Надеюсь, что это поможет!
Ответ 2
У меня такая же проблема, и я попытался решить ее с хорошим ответом Devunwired, но у меня были некоторые проблемы. Я не мог найти способ остановить службу, и когда я закончил свое приложение, GPS-модуль все еще работал. Поэтому я нашел другой способ:
Я написал класс GPS.java:
public class GPS {
private IGPSActivity main;
// Helper for GPS-Position
private LocationListener mlocListener;
private LocationManager mlocManager;
private boolean isRunning;
public GPS(IGPSActivity main) {
this.main = main;
// GPS Position
mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
// GPS Position END
this.isRunning = true;
}
public void stopGPS() {
if(isRunning) {
mlocManager.removeUpdates(mlocListener);
this.isRunning = false;
}
}
public void resumeGPS() {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
this.isRunning = true;
}
public boolean isRunning() {
return this.isRunning;
}
public class MyLocationListener implements LocationListener {
private final String TAG = MyLocationListener.class.getSimpleName();
@Override
public void onLocationChanged(Location loc) {
GPS.this.main.locationChanged(loc.getLongitude(), loc.getLatitude());
}
@Override
public void onProviderDisabled(String provider) {
GPS.this.main.displayGPSSettingsDialog();
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}
Этот класс используется в каждой Деятельности, которая нуждается в координатах GPS. Каждое действие должно реализовать следующий интерфейс (необходимый для связи):
public interface IGPSActivity {
public void locationChanged(double longitude, double latitude);
public void displayGPSSettingsDialog();
}
Теперь моя основная деятельность выглядит так:
public class MainActivity extends Activity implements IGPSActivity {
private GPS gps;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gps = new GPS(this);
}
@Override
protected void onResume() {
if(!gps.isRunning()) gps.resumeGPS();
super.onResume();
}
@Override
protected void onStop() {
gps.stopGPS();
super.onStop();
}
public void locationChanged(double longitude, double latitude) {
Log.d(TAG, "Main-Longitude: " + longitude);
Log.d(TAG, "Main-Latitude: " + latitude);
}
@Override
public void displayGPSSettingsDialog() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
и второй такой:
public class TEST4GPS extends Activity implements IGPSActivity{
private GPS gps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.gps = new GPS(this);
}
@Override
public void locationChanged(double longitude, double latitude) {
Log.d("TEST", "Test-Longitude: " + longitude);
Log.d("TEST", "Test-Latitude: " + latitude);
}
@Override
protected void onResume() {
if(!gps.isRunning()) gps.resumeGPS();
super. onResume();
}
@Override
protected void onStop() {
gps.stopGPS();
super.onStop();
}
@Override
public void displayGPSSettingsDialog() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
Это не так красиво, как решение Devunwired, но оно работает для меня.
суа
Ответ 3
У вас может быть ваша служба, пишущая ваши латы и длинные коорды в sqlite db при изменении таким образом, что у вас нет служебных накладных, и ваши координаты будут доступны во всех ваших действиях.
Возможно, в вашем основном действии вы можете проверить статус GPS, и если он выключен, вы можете предложить пользователю включить его. После того, как GPS включен, запустите службу.
Ответ 4
Вот очень простой и понятный способ сделать это:
В вашей основной деятельности:
private boolean mFinish;
@Override
public void onBackPressed() {
mFinish = true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFinish = false;
...
}
@Override
public void onPause(){
super.onPause();
if (mFinish) {
// remove updates here
mLocationManager.removeUpdates(mLocationListener);
}
}
Это приведет к удалению только прослушивателя обновлений, если вы нажмете Назад в своем основном действии, но в остальном продолжаете.
Это не лучший способ сделать это, но это простое решение для копирования-вставки.
Убедитесь, что вы не вызываете приемник местоположения, если он уже запущен (например, на экране вращается), иначе вы получите несколько прослушивателей, работающих в фоновом режиме.