2010-08-15 11 views
26

Piszę aplikację, która wymaga aktualnej lokalizacji użytkownika (ostatnia lokalizacja nie będzie bardzo pomocna) i wyświetli listę wszystkich najbliższych "pozycji" do nich pobranych z bazy danych.Android raz odnajduje lokalizację GPS, wyświetla okno dialogowe ładowania

Mam ustalenie, że najbliższe elementy działają dobrze, ale tylko na razie używają na stałe ustalonej szerokości i długości geograficznej, ale teraz nadszedł czas, aby zaimplementować znalezienie rzeczywistej lokalizacji.

Każdy może podać przykład, w jaki sposób aplikacja będzie znajdowała bieżącą dokładną lokalizację w tle i będzie czekała aplikacja. Potrzebuję tylko tej lokalizacji, która nie jest aktualizacją, gdy osoba się porusza. Zaimplementowałem odbiornik lokalizacji, ale rozumiem, że uzyskanie poprawki GPS może być powolne. Widziałem inne przykłady używania ostatniej znanej lokalizacji lub implementacji detektora lokalizacji, który nadal działa i aktualizuje się, ponieważ moja Aktywność potrzebuje współrzędnych lokalizacji, zanim będzie mogła wyświetlić wszystko, co tylko się zawiesi. Muszę pokazać okno postępu podczas wyszukiwania.

W jaki sposób można uruchomić przeglądarkę lokalizacji raz w tle, a następnie usunąć aktualizacje lokalizacji po znalezieniu lokalizacji. Potrzebuję pozostałej części aplikacji, aby poczekać, aż znajdzie się lokalizacja GPS lub limit czasu po 20-30 sekundach. Chciałbym, aby ProgressDialog się wyświetlił, aby użytkownik wiedział, że coś się dzieje, ale musi to być tylko obracanie animacji ładowania, nie procent ani nic. Jeśli to możliwe, chciałbym, aby użytkownik mógł anulować okno dialogowe, jeśli ma dość czekania, a następnie może wyszukiwać, wpisując zamiast tego podmiejskie itp.

Próbowałem zrobić to z wątkami, ale robi się znacznie bardziej skomplikowane, niż powinienem być i nadal nie działa. Na iPhonie jest to o wiele prostsze?

Czy ktoś może to zrobić w miły sposób, odrąbałam sobie włosy na tydzień i to naprawdę opóźnia mnie o resztę daty zakończenia aplikacji.

Podsumowując chcę:
* Znajdź aktualne współrzędne
* Pokaż okno postępu podczas pobierania lokalizacja
* Czy aplikacja będzie w stanie czekać na pomyślne lokalizacji lub zrezygnować po pewnym czasie?
* Jeśli powiodło się: Zamknij okno dialogowe postępu i użyj współrzędnych, aby uruchomić inne metody znajdowania elementów w pobliżu.
* Jeśli nie udało się uzyskać lokalizacji: Odrzuć okno dialogowe postępu i wyświetl komunikat o błędzie i zachęć użytkownika do użycia menu, aby przejść do czynności wyszukiwania.
* Użyj tych współrzędnych, jeśli użytkownik wybierze widok mapy z menu, aby pokazać bieżące położenie na mapie i szpilki zrzucone na wszystkie pobliskie elementy, używając ich współrzędnych z bazy danych.

Dzięki chłopaki, mam nadzieję, że wyjaśniłem się wystarczająco dobrze. Wszelkie pytania po prostu zapytaj, będę sprawdzać regularnie, ponieważ chcę, aby ta część została ukończona. Cheers

EDIT
kod na żądanie

plik aktywność 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; 
    } 
}; 

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

To naprawdę wydaje się dużym wysiłkiem, aby tylko raz uzyskać bieżącą lokalizację? Nie wymagam aktualizacji ani niczego? Czy nie ma prostszego sposobu oczekiwania aplikacji na wynik? Utknąłem na tym od tak dawna.

+0

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

Odpowiedz

17

Użyć AsyncTask i używać zarówno network_provider jak gps_provider, co oznacza, że ​​dwa detektory. Gps trwa dłużej, aby uzyskać poprawkę, może czasami minutę i działa tylko na zewnątrz, podczas gdy sieć uzyskuje lokalizację dość szybko.

dobry przykład kodu jest tutaj: What is the simplest and most robust way to get the user's current location on Android?

Dla AsyncTask, patrzeć http://developer.android.com/reference/android/os/AsyncTask.html

Istnieje również wiele przykładowy kod tutaj na SO dla niego, na przykład tutaj: Android Show a dialog until a thread is done and then continue with the program

EDIT: koncepcja kodu:

dodaj zmienną klasy

boolean hasLocation = false; 

rozmowy onCreate (nie w AsyncTask):

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

następnie w locationListener.onLocationChanged zmień wartość po znalezieniu lokalizacji:

boolean hasLocation = false; 

AsyncTask: zostawić jak jest , ale nie wywołuj

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

tam, zamiast robić

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

prawdopodobnie z opóźnieniem między byłoby wystarczające.

+0

Dzięki temu wygląda to pomocne. Myślałem, że rzeczy GPS API były tak czy inaczej asynchroniczne? Czy nadal muszę to wdrożyć, aby aplikacja czekała na wynik? Na podstawie tych przykładów: Tak nazwałbym myLocation.getLocation (this, locationResult) z wewnątrz doInBackground (final String ... args)? Po prostu nie rozumiem, kiedy onPostExecute (ostateczne Void nieużywane) zostanie wywołany jako końcowy wynik rzeczy MyLocation jest getsLocation (ostateczna lokalizacja lokalizacji)? Co się stanie, jeśli zamiast tego skończy się czas? –

+0

Tak, materiał gps jest asynchroniczny, ale pokazujący postęp nie jest. dlatego należy go opakować w AsyncTask, ponieważ okno dialogowe postępu zależy od stanu GPS/wyników. onPostExecute i onPreExecute działają w głównym wątku interfejsu użytkownika, dlatego aktualizujesz swój interfejs użytkownika, np. Gdy masz na przykład naprawę gps, a także zamykasz tam okno dialogowe postępu. –

+0

OK, dzięki, dam ci odpocząć. W jaki sposób onPostExecute wie, kiedy mam naprawę gps lub po jej zakończeniu? to znaczy, skąd wiadomo, kiedy wywołano metodę getsLocation() lub czy skończy się czas? –

12

ja nadal nie podoba, jak to działa w ogóle i wydaje się sposób bardziej skomplikowany niż powinno być, ale dopóki ktoś zapewnia lepszy sposób mam to działa teraz ...

Jeśli ktoś natknie to i sugeruje o wiele lepszy efekt czystszy, aby po prostu uzyskać współrzędne bieżącego położenia użytkownika, a następnie przestać wyglądać, co byłoby bardzo cenione!

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

Od onCreate() wzywam

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

Mam następnie aa prywatną klasy 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 
      } 
     } 
    } 

Następnie locationResult ..

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

również w celu uniknięcia ciągniesz Twoje włosy, tak jak robiłem od wieków, pamiętaj, aby zatrzymać zadanie locationcontrol, jeśli ktoś wcześniej opuści aktywność, a także zatrzymać aktualizacje lokalizacji, aby zatrzymać działanie GPS, gdy użytkownik opuści. W OnStop() zrobić coś takiego:

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

także stopLocationUpdates w klasie Lokalizacja Helper wykonuje następujące operacje:

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

Powodzenia z nim, musiałem go ...

+6

wysyłanie kompletnego działającego kodu (tj. github) byłoby niesamowite dla ciebie i dla nas również :) – ant

0

Zamiast tworzenia AsyncTask, dlaczego nie stworzyłeś pola ProgressDialog i odrzuciłeś je na public void gotLocation(final Location location){}? Możesz również dodać onCancelListener do pola ProgressDialog i anulować wszelkie bieżące żądania lokalizacji.

Powiązane problemy