2010-06-07 19 views
12

Bearbeiten: Ich umforme diese Frage, weil ich anscheinend nicht klar war.Android GPS-Timeout

Manchmal benötigt der GPS-Dienst auf Android-Telefonen eine lange Zeit, um eine Lösung zu finden. Manchmal ist es schnell, manchmal dauert es Stunden. Ich kenne und akzeptiere dies.

Ich habe eine Anwendung, die viele Dinge tut. Sie müssen dem Benutzer beispielsweise ermöglichen, auf eine Schaltfläche zu klicken, um seine aktuellen Koordinaten an einen Server zu senden. Was ich brauche, sind die Koordinaten des Telefons , wenn der Benutzer die Schaltfläche oder innerhalb einer angemessenen kurzen Zeit danach klickt.

Da ich weiß, dass GPS-Fix nicht sofort ist und ich weiß, dass es Minuten oder Stunden dauern kann (während der der Benutzer eine große Entfernung bewegt hat), muss ich eine Zeitüberschreitung für diese Funktion codieren. Für diese Funktion ist es einfach nicht akzeptabel, den GPS-Standort des Benutzers nach dem Klicken auf die Schaltfläche beispielsweise drei Minuten hochzuladen. Es ist in Ordnung, wenn es 45 Sekunden dauert, nicht in Ordnung, wenn es 75 Sekunden dauert. Es ist in Ordnung, dem Benutzer eine Fehlerbenachrichtigung zu geben, wenn die Funktion einen Standort nicht schnell genug abrufen konnte.

Ich brauche eine Funktion, um den GPS-Standort zu erhalten und es an den Server zu senden, , es sei denn, es dauert mehr als eine Minute '.

Mein ursprünglicher Code ist unten. Ich habe einige Dinge seit dem Posten geändert. Ich habe einen Timer in der onStartCommand() Methode hinzugefügt. Ich starte eine TimerTask, die nach 60 Sekunden meine stop() Methode aufruft. Zu Beginn der onLocationChanged() - Methode lehne ich die TimerTask ab.

Meine Frage ist: Ist das Timer-Schema eine gute Möglichkeit, dieses Timeout zu implementieren? Gibt es einen besseren Weg?

Original Frage:

Ich bin eine Android-Anwendung zu schreiben, die unter anderem benötigt, die aktuelle GPS senden an einen Server koordiniert, wenn der Benutzer sagt sie. Von einem Kontextmenü aus führe ich den folgenden Dienst aus. Der Dienst ist ein LocationListener und fordert Aktualisierungen vom LocationManager an. Wenn es einen Speicherort (onLocationChanged()) erhält, entfernt es sich selbst als Listener und sendet die Koordinaten an den Server. All das funktioniert.

Wenn jedoch die GPS-Koordinaten nicht schnell verfügbar sind, läuft mein Dienst nur so lange, bis er wieder verfügbar ist. Es hält die Benutzeroberfläche mit einem Fortschrittsdialog auf, was ärgerlich ist. Schlimmer noch, wenn der Benutzer seit dem Start des Dienstes umgezogen ist, sind die ersten GPS-Koordinaten möglicherweise falsch und die App sendet falsche Daten an den Server.

Ich brauche eine Zeitüberschreitung für den Dienst. Gibt es einen guten Weg, das zu tun? Ich bin nicht sehr erfahren mit Threads. Ich denke, ich kann eine Runnable in der onStartCommand() -Methode ausführen, die irgendwie 30 Sekunden herunterzählen und dann, wenn es noch kein GPS-Ergebnis gibt, die stop() -Methode meines Dienstes aufrufen. Klingt das wie der beste Weg dies zu tun?

Oder ist es möglich zu sagen, ob das GPS nicht repariert werden kann? Wie würde ich das machen?

Bearbeiten: Um weiter zu klären, bin ich auf der Suche nach dem besten Weg, "aufgeben" auf einen Standort nach einiger Zeit.

public class AddCurrentLocation extends Service implements LocationListener { 

    Application app; 
    LocationManager mLocManager; 
    ProgressDialog mDialog; 

    @Override 
    public int onStartCommand(Intent intent, int arg0, int arg1) { 
     app = getApplication(); 

     // show progress dialog 
     if (app.getScreen() != null) { 
      mDialog = ProgressDialog.show(app.getScreen(), "", "Adding Location. Please wait...", true); 
     } 

     // find GPS service and start listening 
     Criteria criteria = new Criteria(); 
     criteria.setAccuracy(Criteria.ACCURACY_FINE); 
     mLocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
     String bestProvider = mLocManager.getBestProvider(criteria, true); 
     mLocManager.requestLocationUpdates(bestProvider, 2000, 0, this); 

     return START_NOT_STICKY; 
    } 

    private void stop() { 
     mLocManager.removeUpdates(this); 
     if (mDialog != null) { 
      mDialog.dismiss(); 
     } 
     stopSelf(); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     // done with GPS stop listening 
     mLocManager.removeUpdates(this); 

     sendLocation(location); // method to send info to server 
     stop(); 
    } 

    // other required methods and sendLocation() ... 

} 
+0

Also was hast du getan, um dies zu lösen? Ich habe das gleiche Problem. – sexitrainer

Antwort

6

Das ist nicht wirklich, wie es funktioniert. In den meisten Situationen wird es so lange dauern, bis ein GPS-Fix verfügbar ist.Von diesem Zeitpunkt an wird jedes Update (alle 2 Sekunden in Ihrem Code) die aktuelle Position der Person sein. Und die erste Lösung, die Sie bekommen, ist die aktuelle Position der Person, so dass die Daten nicht "veraltet" sind.

Eine andere Sache. Wenn Sie diesen Code in einem Dienst ausführen, sollten Sie die Benutzeroberfläche nicht mit einem Fortschrittsdialog und definitiv nicht mit dem Dienst blockieren. Das ist ein Speicherleck, das darauf wartet, passiert zu sein. Sie sollten den Fortschritt nur dann anzeigen, wenn dies höchstens 5 Sekunden dauert und in einem Thread in der Aktivität ausgeführt wird. Eine weitere Option ist, den Fortschrittsdialog in der Titelleiste anzuzeigen und den Benutzer dennoch mit der App interagieren zu lassen (weshalb Sie einen Dienst trotzdem verwenden). Es ist nicht so benutzerfreundlich, wenn man über einen längeren Zeitraum Fortschritte macht. Vor allem, wenn sie die Ausrichtung ändern (vielleicht bei einem Unfall) und dann stürzt Ihre App wegen der Service-Handle auf den Dialog und sie müssen neu beginnen.

Werfen Sie einen Blick auf die Google I/O 2010 app, um ein großartiges Beispiel dafür zu sehen, wie eine Aktivität mit einem Dienst funktionieren sollte. Er verwendet einen Dienst, um Daten zurückzuholen, und zeigt einen Fortschritt im Titel an, während der Dienst etwas Arbeit leistet. Und trotzdem können Sie andere Dinge in der App tun.

+1

Danke für Ihre Hilfe. Was ich tun muss, ist einen einzelnen Ort zu bekommen, wenn der Benutzer eine Kontextmenüoption auswählt. Also, wenn es 15 Minuten dauert, um ein GPS-Update zu bekommen (und es hat manchmal auf meinem Handy), dann wird diese Position veraltet sein. Grundsätzlich möchte ich wissen, wo der Benutzer war, als er auf den Knopf klickte und wenn es zu lange dauert (was auch immer das sein mag), dann muss ich dem Benutzer sagen, dass die Funktion fehlgeschlagen ist. In den meisten Fällen wird der Benutzer dort sitzen und das Telefon beobachten, um zu sehen, ob es funktioniert. Ich kann sie einfach stundenlang ohne GPS-Signal dort sitzen lassen :) –

+0

Wenn das der Fall ist, dann warum starten Sie GPS nicht richtig, wenn die App startet und dann, wenn sie den Knopf drücken, wird es wahrscheinlich schon eine Lösung haben . Und wie ich schon sagte. Mit GPS wird der Standort nicht veraltet sein. Es wird behoben und die Standortaktualisierung wird der aktuelle Standort des Telefons sein. –

+0

Ich habe meine Frage bearbeitet, um klarer zu sein. –

4

Scott, es gibt viele Faktoren, die beeinflussen, wie lange eine erste Reparatur dauern kann - oder ob eine Reparatur möglich ist. Die häufigsten sind physische Hindernisse zwischen dem Gerät und Satelliten (wie Gebäude, Canyonwände usw.) .

Sie können nicht kontrollieren, wie lange es für die GPS-Maschine nimmt ein Update zu liefern, aber man kann sagen, wie seine tun, einschließlich der Zeit des ersten fix:

locationManager.addGpsStatusListener(gpsListener); 

    // this reports on the status of the GPS engine, but does not enable additional controls 
    private static final GpsStatus.Listener gpsListener = new GpsStatus.Listener() { 
     public void onGpsStatusChanged(int event) { 
      GpsStatus gpsStatus = locationManager.getGpsStatus(null); 
      switch (event) { 
       case GpsStatus.GPS_EVENT_STARTED: 
        Log.i(TAG, "onGpsStatusChanged(): GPS started"); 
        break; 
       case GpsStatus.GPS_EVENT_FIRST_FIX: 
        Log.i(TAG, "onGpsStatusChanged(): time to first fix in ms = " + gpsStatus.getTimeToFirstFix()); 
        break; 
       case GpsStatus.GPS_EVENT_SATELLITE_STATUS: 
        // int maxSatellites = gpsStatus.getMaxSatellites(); // appears fixed at 255 
        // if (H.DEBUG) Log.d(TAG, "onGpsStatusChanged(): max sats = " + maxSatellites); 
        if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): ##,used,s/n,az,el"); 
        Iterable<GpsSatellite>satellites = gpsStatus.getSatellites(); 
        Iterator<GpsSatellite>satI = satellites.iterator(); 
        while (satI.hasNext()) { 
         GpsSatellite satellite = satI.next(); 
         if (H.VERBOSE) Log.d(TAG, "onGpsStatusChanged(): " + satellite.getPrn() + "," + satellite.usedInFix() + "," + satellite.getSnr() + "," + satellite.getAzimuth() + "," + satellite.getElevation()); 
         // http://en.wikipedia.org/wiki/Global_Positioning_System: the almanac consists of coarse orbit and status information for each satellite 
         // http://en.wikipedia.org/wiki/Ephemeris: the positions of astronomical objects in the sky at a given time 
         // + "," + satellite.hasAlmanac() + "," + satellite.hasEphemeris()); 
        } 
        break; 
       case GpsStatus.GPS_EVENT_STOPPED: 
        Log.i(TAG, "onGpsStatusChanged(): GPS stopped"); 
        break; 
      }  
     } 
    }; 

Events wird als Motor erzeugt werden versucht, verfügbare Satelliten zu hören. Bei einem kürzlichen Test mit Lichthindernissen fand ich heraus, dass es 22,4 Sekunden dauerte, um eine erste Lösung zu finden, bei der 24 SATELLITE_STATUS Ereignisse den allmählichen Zugriff von 8 Satelliten berichteten, bevor ausreichend saubere Signale empfangen wurden. Hier ist das letzte Ereignis:

06-08 23: 25.147, D, GPS, 22427, "onGpsStatusChanged(): ##, verwendet, s/n, az, el" 06-08 23:23 : 25.147, D, GPS, 22427, "onGpsStatusChanged(): 2, richtig, 26,0,57,0,73.0" 06-08 23: 23: 25.147, D, GPS, 22427, "onGpsStatusChanged(): 4, richtig, 30.0 , 46,0,27,0 " 06-08 23: 23: 25.147, D, GPS, 22427," onGpsStatusChanged(): 5, richtig, 19.0.144.0,25.0 " 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 9, richtig, 22.0.202.0,22.0" 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 10, richtig, 17.0.109.0,32.0" 06 -08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 12, richtig, 32.0.320.0,80.0" 06-08 23: 25: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 29, richtig, 21,0,278,0,21,0 " 06-08 23: 23: 25.155, D, GPS, 22427, "onGpsStatusChanged(): 30, wahr, 31.0, 312.0, 43.0" 06-08 23: 23: 25.163, D, GpsLocationProvider, 1039, TTFF: 22457 06-08 23: 23: 25,194, I, GPS, 22427, onGpsStatusChanged(): time to first fix in ms = 22457

Beachten Sie, dass Sie auf einmal fix Zeit, werden Sie den aktuellen Standort bekommen, nicht wo könnte gewesen sein. Ich denke zusammen mit dem, was du schon hast, kannst du jetzt dorthin kommen. Oder, überprüfen Sie, wie die Profis es tun here.

+0

Danke für Ihre Hilfe. Ich habe meine Frage bearbeitet, um klarer zu sein. –

+0

@DJC, bitte korrigieren Sie den fehlerhaften Link zu MyTracks.java. – Gili

+0

Was ist H im Code? – Siddhesh

-7

zu Shawn auf die Antwort Basierend, packen die Parameter in JSON und die JSON-Objekte in den Server senden

1

ich mit einem ähnlichen Problem zu kämpfen haben und vor kurzem von einem Zeitgeber auf einen AlarmManager geschaltet , die viel robuster zu sein scheint. Das könnte für Ihre Situation ein Overkill sein (ich benutze dies für wiederholte Standortproben), aber Sie sollten zumindest einen Handler anstelle des Timers verwenden. (Verwenden Sie Handler.postDelayed.)

Verwandte Themen