programacion - Android: la mejor forma de implementar LocationListener en múltiples actividades
manual de android en pdf (4)
He estado atascado en este problema por bastante tiempo. Estoy trabajando en una aplicación que usa la ubicación bastante extensamente en varias actividades diferentes. Cada ejemplo que he encontrado utiliza un LocationListener por separado en cada actividad. Esto no es factible en mi situación.
Me pregunto cuál es la forma más eficiente de realizar un seguimiento de la ubicación del usuario en varias actividades. En este momento, he creado un servicio que implementa LocationListener y usa una transmisión para actualizar latitud estática y campos largos en una clase base de actividad. Esto significa que el servicio siempre se está ejecutando, lo que no es ideal. Pero si apago el servicio y lo reinicio solo cuando lo necesito, toma tiempo obtener una buena ubicación. Necesito los datos de ubicación en Activity onCreate (). Es lo mismo si trato de implementarlo en la clase base de la actividad. Si registro constantemente el oyente en onResume / onCreate y lo anulo en onPause (), lleva demasiado tiempo comenzar a recibir actualizaciones. También traté de crear un servicio al que pudiera vincularme, por lo que solo comienza cuando necesito una ubicación. Pero tengo el mismo problema, lleva demasiado tiempo enlazar al servicio y comenzar a recibir actualizaciones.
El servicio que estoy usando ahora funciona, pero de todo lo que he leído, no debería estar usando un servicio en funcionamiento constante para cosas triviales como esta. Pero el objetivo de la aplicación es proporcionar datos relevantes basados en la ubicación actual del usuario. Así que tengo un servicio que se ejecuta en segundo plano y proporciona actualizaciones periódicamente. El principal problema que me ha llevado a reexaminar el diseño en este momento es que recientemente descubrí que onProviderEnabled () no se llama si el usuario inicia la aplicación sin que el GPS esté encendido y luego lo habilita. En este escenario, la aplicación no tiene forma de reconocer que el GPS estaba habilitado para que pueda comenzar a escuchar las actualizaciones.
Creí entender que LocationManager y LocationListener miraban los ejemplos, pero parece que no puedo aplicarlo a esta situación en la que necesito datos de ubicación en múltiples actividades. Cualquier ayuda o consejo sería muy apreciado.
Aquí hay una manera muy simple y directa de hacerlo:
En tu actividad principal:
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);
}
}
Esto solo eliminará el oyente de actualizaciones si presiona Atrás en su actividad principal, pero de lo contrario permanecerá encendido.
No es la mejor manera de hacerlo, pero es una solución simple de copiar y pegar.
Asegúrese de no llamar al oyente de ubicación si ya se está ejecutando (por ejemplo, al girar la pantalla), de lo contrario, terminará con múltiples oyentes ejecutándose en segundo plano.
La forma en que normalmente implementaría este requisito es utilizando una implementación de servicio enlazado, como la que se encuentra en el ejemplo de servicio local en la documentación del SDK. Obviamente, está familiarizado con la ventaja del Servicio que le permite crear todo el código de ubicación solo una vez.
El acceso al Servicio a través de Vinculaciones permite que el Servicio se inicie y se detenga, por lo que no se ejecuta cuando su aplicación no está en primer plano (morirá tan pronto como no haya más Actividades vinculadas). La clave, IMO, para hacer que esto funcione bien es onStart()
el servicio en onStart()
y UNBIND en onStop()
, porque esas dos llamadas se superponen cuando pasas de una actividad a otra (la segunda actividad comienza antes de que la primera se detenga). Esto evita que el Servicio muera cuando se mueve dentro de la aplicación, y solo deja que el servicio muera cuando toda la aplicación (o al menos cualquier parte interesada en la ubicación) abandona el primer plano.
Con los enlaces, no tiene que pasar los datos de ubicación en una difusión, porque la actividad puede llamar a los métodos directamente en el servicio para obtener la última ubicación. Sin embargo, una Transmisión aún sería ventajoso como método para indicar CUÁNDO está disponible una nueva actualización ... pero esto se convertiría en un notificador a la Actividad de escucha para llamar al método getLocation()
en el Servicio.
Mi $ 0.02. ¡Espero que ayude!
Puede hacer que su servicio escriba sus coordenadas lat & long en un sqlite db en el cambio de esa manera no tiene el servicio vinculante y sus coords estarán accesibles en todas sus actividades.
Quizás en su actividad principal puede verificar el estado del GPS y, si está apagado, puede solicitarle al usuario que lo habilite. Una vez que el GPS está habilitado, inicie su servicio.
Tuve el mismo problema e intenté resolverlo con la buena respuesta de Devunwired, pero tuve algunos problemas. No pude encontrar una manera de detener el servicio y cuando terminé mi aplicación, el módulo GPS aún se estaba ejecutando. Entonces encontré otra forma:
Escribí una clase 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) {
}
}
}
Esta clase se usa en cada actividad que necesita las coordenadas GPS. Cada actividad tiene que implementar la siguiente interfaz (necesaria para la comunicación):
public interface IGPSActivity {
public void locationChanged(double longitude, double latitude);
public void displayGPSSettingsDialog();
}
Ahora mi actividad principal se ve así:
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);
}
}
y un segundo así:
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);
}
}
No es tan hermoso como la solución de Devunwired, pero funciona para mí. cya