2010-08-15 16 views
26

Estoy escribiendo una aplicación que requiere la ubicación actual del usuario (lastknownlocation no será muy útil) y muestra una lista de todos los "elementos" más cercanos a ellos tomados de la base de datos.Android Buscar ubicación GPS una vez, mostrar cuadro de diálogo de carga

He encontrado que los artículos más cercanos funcionan bien pero solo usando una ubicación de latitud y longitud codificada por el momento, pero ahora es el momento de implementar la búsqueda de la ubicación real.

¿Alguien puede dar un ejemplo de cómo hacer que la aplicación encuentre la ubicación correcta actual en segundo plano y que la aplicación espere? Solo necesito la ubicación una vez que no se actualiza a medida que la persona se mueve. Implementé un oyente de ubicación, sin embargo, entiendo que la corrección de un GPS puede ser lenta. He visto otros ejemplos utilizando la última ubicación conocida o implementando el receptor de la ubicación, que continúa ejecutándose y actualizándose, sin embargo, como mi actividad necesita las coordenadas de ubicación antes de que pueda mostrar cualquier cosa que la aplicación simplemente bloquee. Necesito mostrar un cuadro de diálogo de progreso mientras busco.

¿Cómo puedo hacer que el localizador se ejecute una vez en segundo plano y luego eliminar las actualizaciones de ubicación una vez que encuentra la ubicación. Necesito que el resto de la aplicación espere hasta que tenga una ubicación GPS o tiempo de espera después de decir 20-30segundos. Me gustaría un ProgressDialog para que el usuario sepa que algo está pasando, pero tiene que ser la animación de carga giratoria no un porcentaje ni nada. Si es posible, me gustaría que el usuario pueda cancelar el diálogo si está harto de esperar, para luego buscarlo escribiendo suburbio, etc.

He estado tratando de hacerlo con hilos, pero se está volviendo mucho más complicado de lo que creo que debería ser y todavía no funciona de todos modos. En iPhone esto es mucho más simple?

¿Alguien puede proporcionar una buena manera de hacer esto, he estado rompiéndome el cabello por una semana en esto y realmente me está retrasando por el resto de la fecha de finalización de la aplicación.

En resumen, quieren:
* Encuentra las coordenadas actuales
* Mostrar progresión al obtener la ubicación
* tener aplicación sea capaz de esperar para la localización exitosa o renunciar después de un cierto tiempo?
* If Successful: desestima el cuadro de diálogo Progress y usa las coordenadas para ejecutar mis otros métodos para encontrar elementos cercanos.
* Si no se pudo obtener la ubicación: descarte el cuadro de diálogo de progreso y muestre el mensaje de error, y anime al usuario a usar el menú para ir a la Actividad de búsqueda.
* Utilice estas coordenadas si el usuario elige la vista del mapa desde el menú, para mostrar la ubicación actual en el mapa y los pines eliminados en todos los elementos cercanos utilizando sus coordenadas de la base de datos.

Gracias chicos, espero haberme explicado lo suficiente. Si tiene alguna pregunta, lo visitaré regularmente ya que estoy ansioso por completar esta parte.Saludos

EDITAR
Código conforme a lo solicitado

fichero de actividad locationList

protected void onStart() 
{ 
    super.onStart(); 

    // .... 

    new LocationControl().execute(this); 
} 


private class LocationControl extends AsyncTask<Context, Void, Void> 
{ 
    private final ProgressDialog dialog = new ProgressDialog(branchAtmList.this); 

    protected void onPreExecute() 
    { 
     this.dialog.setMessage("Determining your location..."); 
     this.dialog.show(); 
    } 

    protected Void doInBackground(Context... params) 
    { 
     LocationHelper location = new LocationHelper(); 

     location.getLocation(params[0], locationResult); 

     return null; 
    } 

    protected void onPostExecute(final Void unused) 
    { 
     if(this.dialog.isShowing()) 
     { 
      this.dialog.dismiss(); 
     } 

     useLocation(); //does the stuff that requires current location 
    } 

} 

public LocationResult locationResult = new LocationResult() 
{ 
    @Override 
    public void gotLocation(final Location location) 
    { 
     currentLocation = location; 
    } 
}; 

clase LocationHelper

package org.xxx.xxx.utils; 

import java.util.Timer; 
/* 
imports 
*/ 

public class LocationHelper 
{ 
    LocationManager locationManager; 
    private LocationResult locationResult; 
    boolean gpsEnabled = false; 
    boolean networkEnabled = false; 

    public boolean getLocation(Context context, LocationResult result) 
    {  
     locationResult = result; 

     if(locationManager == null) 
     { 
      locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); 
     } 
      //exceptions thrown if provider not enabled 
      try 
      { 
       gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
      } 
      catch (Exception ex) {} 
      try 
      { 
       networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
      } 
      catch (Exception ex) {} 

      //dont start listeners if no provider is enabled 
      if(!gpsEnabled && !networkEnabled) 
      { 
       return false; 
      } 

      if(gpsEnabled) 
      { 
       locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps); 
      } 
      if(networkEnabled) 
      { 
       locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork); 
      } 


      GetLastLocation(); 
      return true; 
    } 

    LocationListener locationListenerGps = new LocationListener() { 
     public void onLocationChanged(Location location) 
     { 
      locationResult.gotLocation(location); 
      locationManager.removeUpdates(this); 
      locationManager.removeUpdates(locationListenerNetwork); 

     } 
     public void onProviderDisabled(String provider) {} 
     public void onProviderEnabled(String provider) {} 
     public void onStatusChanged(String provider, int status, Bundle extra) {} 
    }; 

    LocationListener locationListenerNetwork = new LocationListener() { 
     public void onLocationChanged(Location location) 
     { 
      locationResult.gotLocation(location); 
      locationManager.removeUpdates(this); 
      locationManager.removeUpdates(locationListenerGps); 

     } 
     public void onProviderDisabled(String provider) {} 
     public void onProviderEnabled(String provider) {} 
     public void onStatusChanged(String provider, int status, Bundle extra) {} 

    }; 

    private void GetLastLocation() 
    { 
      locationManager.removeUpdates(locationListenerGps); 
      locationManager.removeUpdates(locationListenerNetwork); 

      Location gpsLocation = null; 
      Location networkLocation = null; 

      if(gpsEnabled) 
      { 
       gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
      } 
      if(networkEnabled) 
      { 
       networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
      } 

      //if there are both values use the latest one 
      if(gpsLocation != null && networkLocation != null) 
      { 
       if(gpsLocation.getTime() > networkLocation.getTime()) 
       { 
        locationResult.gotLocation(gpsLocation); 
       } 
       else 
       { 
        locationResult.gotLocation(networkLocation); 
       } 

       return; 
      } 

      if(gpsLocation != null) 
      { 
       locationResult.gotLocation(gpsLocation); 
       return; 
      } 

      if(networkLocation != null) 
      { 
       locationResult.gotLocation(networkLocation); 
       return; 
      } 

      locationResult.gotLocation(null); 
    } 

    public static abstract class LocationResult 
    { 
     public abstract void gotLocation(Location location); 
    } 
} 

Esto realmente parece un gran esfuerzo solo para obtener la ubicación actual una vez? No necesito actualizaciones ni nada? ¿No hay una forma más simple de que la aplicación espere un resultado? He estado atrapado en esto por tanto tiempo.

+0

http://stackoverflow.com/questions/3145089/what-is-the-simplest-and-most-robust-way-to-get-the-users-current-location-in-a/9811633#9811633 – Rajal

Respuesta

17

Utilice un AsyncTask y utilizar tanto network_provider así como gps_provider, lo que significa dos oyentes. Los gps tardan más en solucionarse, tal vez a veces un minuto y solo funcionan al aire libre, mientras que la red obtiene una ubicación bastante rápida.

Un buen ejemplo de código está aquí: What is the simplest and most robust way to get the user's current location on Android?

Para AsyncTask, mira http://developer.android.com/reference/android/os/AsyncTask.html

También hay muchos ejemplo de código aquí en SO para ello, por ejemplo aquí: Android Show a dialog until a thread is done and then continue with the program

EDIT: concepto de código:

agregar clase variable

boolean hasLocation = false; 

llamada en onCreate (no en AsyncTask):

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); 
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); 

después en locationListener.onLocationChanged, cambie el valor una vez que se encuentra una ubicación:

boolean hasLocation = false; 

AsyncTask: licencia, ya que es , pero no llame a

LocationHelper location = new LocationHelper(); 
location.getLocation(params[0], locationResult); 

allí, en lugar hacerlo

Long t = Calendar.getInstance().getTimeInMillies(); 
while (!hasLocation && Calendar.getInstance().getTimeInMillies()-t<30000)) { 
    Thread.Sleep(1000); 
};  

probablemente con un retraso en el medio sería suficiente.

+0

Gracias, esto parece útil. Pensé que las API de GPS eran asíncronas de todos modos? ¿O aún necesito implementar esto para que la aplicación espere un resultado? Basado en esos ejemplos: Entonces, ¿llamaría myLocation.getLocation (this, locationResult) desde doInBackground (final String ... args)? Simplemente no entiendo cuando onPostExecute (void final sin usar) se llamaría ya que el resultado final de las cosas de MyLocation es getLocation (ubicación de ubicación final)? ¿Qué sucede si el temporizador se agota en su lugar? –

+0

sí, las cosas gps son asíncronas, pero mostrar un progreso no lo es. por lo tanto, debe envolverlo en una AsyncTask, ya que el diálogo de progreso depende de su estado/resultados de gps. onPostExecute y onPreExecute se ejecutan en el subproceso principal de la interfaz de usuario, por lo tanto, actualiza la interfaz de usuario allí, es decir, una vez que tiene una solución gps por ejemplo, y también descarta el diálogo de progreso allí. –

+0

Bien, gracias, voy a intentarlo. ¿Cómo sabe onPostExecute cuándo tengo una solución gps o cuándo ha terminado de ejecutarse? es decir, ¿cómo sabe cuándo se llama a gotLocation() o se acaba el tiempo? –

12

Todavía no me gusta la forma en que esto funciona en absoluto y parece mucho más complicado de lo que debería ser, pero hasta que alguien ofrece una mejor manera que tengo que trabajar por ahora ...

Si alguien viene a través de esto y sugerir un resultado de limpieza mucho mejor para obtener solo las coordenadas de ubicación actuales del usuario una vez y luego dejar de buscar que serían muy apreciadas !!

private LocationControl locationControlTask; 
private boolean hasLocation = false; 
LocationHelper locHelper; 

De onCreate() me llame

locHelper = new LocationHelper(); 
locHelper.getLocation(context, locationResult); 
locationControlTask = new LocationControl(); 
locationControlTask.execute(this); 

entonces tengo aa LocationControl clase privada

private class LocationControl extends AsyncTask<Context, Void, Void> 
    { 
     private final ProgressDialog dialog = new ProgressDialog(activityname.this); 

     protected void onPreExecute() 
     { 
      this.dialog.setMessage("Searching"); 
      this.dialog.show(); 
     } 

     protected Void doInBackground(Context... params) 
     { 
      //Wait 10 seconds to see if we can get a location from either network or GPS, otherwise stop 
      Long t = Calendar.getInstance().getTimeInMillis(); 
      while (!hasLocation && Calendar.getInstance().getTimeInMillis() - t < 15000) { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      }; 
      return null; 
     } 

     protected void onPostExecute(final Void unused) 
     { 
      if(this.dialog.isShowing()) 
      { 
       this.dialog.dismiss(); 
      } 

      if (currentLocation != null) 
      { 
       useLocation(); 
      } 
      else 
      { 
       //Couldn't find location, do something like show an alert dialog 
      } 
     } 
    } 

A continuación, un locationResult ..

public LocationResult locationResult = new LocationResult() 
    { 
     @Override 
     public void gotLocation(final Location location) 
     { 
      currentLocation = new Location(location); 
      hasLocation = true; 
     } 
    }; 

también para evitar usted tirando Con los pelos caídos como lo hice durante siglos, recuerde detener la tarea de control de ubicación si alguien abandona la actividad antes de tiempo y también detiene las actualizaciones de ubicación para evitar que el GPS se ejecute cuando el usuario se vaya. En onStop() hacer algo como esto:

locHelper.stopLocationUpdates(); 
locationControlTask.cancel(true); 

también stopLocationUpdates en la clase Ayudante de Lugar realiza lo siguiente:

public void stopLocationUpdates() 
{ 
locationManager.removeUpdates(locationListenerGps); 
locationManager.removeUpdates(locationListenerNetwork); 
} 

Buena suerte con ella, lo necesitaba ...

+6

publicando el código de trabajo completo (es decir, github) sería increíble para ti y para nosotros también :) – ant

0

lugar de crear una AsyncTask ¿por qué no creó un cuadro de diálogo de progreso y lo descartó en public void gotLocation(final Location location){}? También puede agregar un onCancelListener al cuadro de diálogo ProgressDialog y cancelar cualquier solicitud de ubicación actual.

Cuestiones relacionadas