2010-08-15 10 views
26

Ich schreibe eine App, die den aktuellen Standort des Benutzers benötigt (letzte bekannte Position wird nicht sehr hilfreich sein) und zeigt eine Liste aller aus der Datenbank entnommenen "Objekte" an.Android GPS-Ort einmal finden, Ladedialog anzeigen

Ich habe das Finden der nächsten Elemente gut funktioniert, aber nur mit einem hartcodierten Breiten- und Längengrad Ort für die Zeit, aber jetzt ist es an der Zeit, den tatsächlichen Standort zu finden.

Kann jemand ein Beispiel dafür geben, wie die App den aktuellen Standort im Hintergrund finden und die App warten lassen kann. Ich brauche den Ort nur einmal nicht aktualisiert, wenn sich die Person bewegt. Ich habe einen Standort-Listener implementiert, aber ich verstehe, dass ein GPS-Fix langsam sein kann. Ich habe andere Beispiele gesehen, die den letzten bekannten Ort verwenden oder den Lokalisierungs-Listener implementieren, der jedoch weiterläuft und aktualisiert wird, da meine Aktivität die Standortkoordinaten benötigt, bevor sie alles anzeigen kann, was gerade abstürzt. Ich muss während der Suche einen Fortschrittsdialog anzeigen.

Wie kann ich den LocationListener einmal im Hintergrund ausgeführt und dann Standort-Updates entfernen, sobald es den Speicherort findet. Ich brauche den Rest der Anwendung zu warten, bis es eine GPS-Position oder Timeout nach sagen 20-30 Sekunden hat. Ich möchte einen ProgressDialog, damit der Benutzer weiß, dass etwas läuft, aber es muss nur die drehende Lade-Animation sein, kein Prozentsatz oder so. Wenn möglich, möchte ich, dass der Benutzer in der Lage ist, den Dialog abzubrechen, wenn er es satt hat zu warten, und dann suchen kann, indem er stattdessen Vorort usw. eingibt.

Ich habe versucht, es mit Threads zu tun, aber es wird viel komplizierter als ich denke, es sollte immer noch nicht funktionieren. Auf dem iPhone ist das viel einfacher?

Kann mir jemand eine gute Möglichkeit bieten, dies zu tun, habe ich mir eine Woche lang die Haare ausgerissen und es bringt mich wirklich in Verlegenheit für den Rest des App-Abschlussdatums.

Zusammenfassend mag ich:
* aktuelle Koordinaten finden
* Status anzeigen Dialog, während ich Standort
* Haben App für erfolgreichen Standort oder gibt nach einer gewissen Zeit warten kann?
* Wenn erfolgreich: Fortschrittsdialog abbrechen und Koordinaten verwenden, um meine anderen Methoden zum Suchen von Elementen in der Nähe auszuführen.
* Wenn das Abrufen des Standorts fehlgeschlagen ist: Fortschrittsdialog abbrechen und eine Fehlermeldung anzeigen und den Benutzer ermutigen, das Menü zu verwenden, um zu Suchen Aktivität zu gehen.
* Verwenden Sie diese Koordinaten, wenn der Benutzer die Kartenansicht aus dem Menü auswählt, um den aktuellen Standort auf der Karte und die Pins aller Objekte in der Nähe anzuzeigen, indem ihre Koordinaten aus der Datenbank verwendet werden.

Danke Jungs, ich hoffe, ich habe mich gut genug erklärt. Haben Sie Fragen, fragen Sie einfach, ich werde regelmäßig nachsehen, da ich gerne diesen Teil vervollständigen möchte. Prost

EDIT
-Code als angefordert

locationList Aktivitätsdatei

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; 
    } 
}; 

LocationHelper Klasse

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); 
    } 
} 

Das scheint wirklich eine große Anstrengung zu sein, nur um den aktuellen Standort einmal zu bekommen? Ich brauche keine Updates oder irgendetwas? Gibt es keine einfachere Möglichkeit, die Anwendung auf ein Ergebnis warten zu lassen? Ich habe mich so lange festgefahren.

+0

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

Antwort

17

Verwenden eines AsyncTask und verwendet sowohl network_provider sowie gps_provider, die zwei Hörer bedeuten. gps dauert länger, um eine Reparatur zu bekommen, vielleicht manchmal eine Minute und funktioniert nur im Freien, während das Netzwerk ziemlich schnell einen Standort bekommt.

Ein gutes Codebeispiel ist hier: What is the simplest and most robust way to get the user's current location on Android?

Für AsyncTask, schauen http://developer.android.com/reference/android/os/AsyncTask.html

Hier gibt es auch viele Codes sind beispielsweise auf SO für sie, zum Beispiel hier: Android Show a dialog until a thread is done and then continue with the program

EDIT: Code-Konzept:

Klasse hinzufügen Variable

boolean hasLocation = false; 

Anruf in onCreate (nicht in AsyncTask):

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

dann in locationListener.onLocationChanged, den Wert ändern, sobald ein Standort gefunden wird:

boolean hasLocation = false; 

AsyncTask: lassen, wie es ist , aber nicht anrufen

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

dort tun, anstatt

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

wahrscheinlich mit einer Verzögerung zwischen ausreichen würde.

+0

Danke das sieht hilfreich aus. Ich dachte GPS GPS Sachen waren sowieso asynchron? Oder muss ich das noch implementieren, damit die App auf ein Ergebnis wartet? Basierend auf diesen Beispielen: So würde ich myLocation.getLocation (this, locationResult) aus doInBackground (final String ... args) aufrufen? Ich verstehe nur nicht wirklich, wenn onPostExecute (endgültige Void unbenutzt) würde als das Ergebnis der MyLocation stuff aufgerufen werden gotLocation (endgültige Location location)? Was passiert auch, wenn der Timer abgelaufen ist? –

+0

ja das GPS-Zeug ist async, aber einen Fortschritt zeigt es nicht. Daher müssen Sie es in eine AsyncTask einbinden, da der Fortschrittsdialog von Ihrem GPS-Status/den Ergebnissen abhängt. onPostExecute und onPreExecute werden auf dem Hauptthread der Benutzeroberfläche ausgeführt, daher aktualisieren Sie Ihre Benutzeroberfläche dort, d. H. Nachdem Sie beispielsweise einen GPS-Fix erhalten haben, und schließen Sie den Fortschrittsdialog dort ab. –

+0

Ok danke ich werde es versuchen. Wie weiß onPostExecute, wenn ich eine GPS-Korrektur habe oder wenn die Ausführung beendet ist? dh wie weiß es, wenn entweder gotLocation() aufgerufen wird oder der Timer abgelaufen ist? –

12

ich immer noch nicht mag, wie das überhaupt funktioniert und es scheint Art und Weise komplizierter, als es sein sollte, aber bis jemand einen besseren Weg bietet es für mich jetzt arbeiten, haben ...

Wenn jemand kommt über dies und schlagen ein viel besseres sauberes Ergebnis vor, um nur die aktuellen Standortkoordinaten des Benutzers nur einmal zu erhalten, dann aufhören zu suchen, das würde sehr geschätzt werden !!

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

Von onCreate() Ich

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

nennen Ich habe dann einen Privat Klasse LocationControl

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 
      } 
     } 
    } 

Dann wird ein locationResult ..

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

auch zu vermeiden du ziehst Ihr Haar, wie ich es schon seit Ewigkeiten getan habe, erinnert Sie daran, die Location-Control-Aufgabe zu beenden, wenn jemand die Aktivität vorzeitig verlässt und auch Standort-Updates stoppt, um das GPS zu stoppen, wenn der Benutzer geht. In OnStop() etwas tun, wie folgt aus:

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

Auch stopLocationUpdates in der Lage Helper Klasse macht folgendes:

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

Viel Glück mit ihm, ich brauchte es ...

+6

posten vollständigen Arbeitscode (d. h. github) wäre toll für Sie und für uns auch :) – ant

0

Statt Erstellen einer AsyncTask Warum haben Sie nicht ein ProgressDialog-Feld erstellen und es unter public void gotLocation(final Location location){} ablehnen? Sie können dem ProgressDialog-Feld auch einen onCancelListener hinzufügen und alle aktuellen Standortanforderungen abbrechen.