2013-06-15 13 views
9

Sto sviluppando un'applicazione che elenca i ristoranti più vicini all'utente. Quando si fa clic sul pulsante di aggiornamento, elenca i ristoranti per la posizione corrente dell'utente. Sto usando il Location Manager e richiedo aggiornamenti solo quando l'attività arriva in primo piano (onResume) per evitare l'uso costante della batteria. Quando l'app entra in onPause(), gli aggiornamenti di posizione vengono interrotti. Funziona perfettamente con l'emulatore quando passo gli aggiornamenti attraverso il terminale.Android locationManager requestLocationUpdates non funziona

Problema: Problema: Quando cambio la mia posizione fisica (ad esempio, guida a 5 miglia di fino a quel momento l'app continua a mostrare i ristoranti per la posizione precedente. Ma se cambio fisicamente la mia posizione e accedo a Google Maps e poi apro la mia applicazione ristorante, allora funziona istantaneamente. Mi sono assicurato che il GPS sia acceso. Cosa posso fare per far sì che il Location Manager esegua l'avvio e aggiorni la posizione non appena apro la mia attività? Grazie in anticipo!

package com.mortley.android.restaurantsaver; 

public class NearbyRestaurantActivity extends ListActivity implements OnClickListener, LocationListener{ 
    private Button refreshButton, searchRestaurants; 
    ImageButton goToSearch; 
    private double[] lastKnownLocation; 
    private EditText locationEditText; 
    private LocationManager locManager; 
    private LocationListener locListener; 
    private boolean gps_enabled = false; 
    private boolean network_enabled = false; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.nearbyrestaurants); 
     refreshButton = (Button)findViewById(R.id.reloadButton); 
     refreshButton.setOnClickListener(this); 

     searchRestaurants = (Button)findViewById(R.id.searchButton); 
     searchRestaurants.setOnClickListener(this); 
     goToSearch = (ImageButton)findViewById(R.id.goLocationButton); 
     goToSearch.setOnClickListener(this); 
     locationEditText = (EditText)findViewById(R.id.addressTextBox); 
     locationEditText.setVisibility(View.GONE); 
     goToSearch.setVisibility(View.GONE); 

     locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);//?? 


     locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 100, this); 

     //checks network connectivity 
     boolean checkConnection = isNetworkAvailable(); 
     if(!checkConnection){ 
      Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show(); 
     } 

     if(checkConnection){ 
      //sets current location parameters for the user 
      lastKnownLocation = RestaurantHelper.getLastKnownLocation(this); 
      //Log.v("NearbyRestaurantActivity", "This"+this); 

      RestaurantApplication application = (RestaurantApplication) this.getApplication(); 
      RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label,new ArrayList<RestaurantReference>()); 
      restaurantAdapter.setLastKnownLocation(lastKnownLocation); 


      //set a global variable for the RestaurantAdapter in the RestaurantApplication class. 
      application.setRestaurantAdapter(restaurantAdapter); 
      //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call. 
      setListAdapter(restaurantAdapter); 
      //Make a webservice call in a different thread passing Keyword for URL as a string array. 
      RestaurantHttpAsyncTask m_progressTask; 
      String[] keywords = {"", "american", "asian", "italian","mexican"}; 
      //String[] keywords = {"indian"}; 
      m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords); 
      m_progressTask.setRestaurantAdapter(restaurantAdapter); 
      m_progressTask.execute(); 
     } 
    } 

    @Override 
    public void onClick(View v) { 
     //Refresh button helps to refresh the restaurant list on location change. Again it makes a call to the webservice using Async Task 
     if(v.getId() == refreshButton.getId()){ 


      try { 
       gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
      } catch (Exception ex) { 
       ex.printStackTrace(); 
      } 
      try { 
       network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
      } catch (Exception ex) { 
       ex.printStackTrace(); 
      } 

      // don't start listeners if no provider is enabled 
      if (!gps_enabled && !network_enabled) { 
       Toast.makeText(getApplicationContext(), "Sorry, Location is not determined. Please enable your Network Providers.", Toast.LENGTH_LONG).show(); 


      } 

      //check network connectivity before refresh 
      boolean checkConnection = isNetworkAvailable(); 
      if(!checkConnection){ 
       Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show(); 
      } 
      if(checkConnection){ 

       RestaurantApplication application = (RestaurantApplication) this.getApplication(); 
       RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label, new ArrayList<RestaurantReference>()); 
       restaurantAdapter.setLastKnownLocation(lastKnownLocation); 
       //set a global variable for the RestaurantAdapter in the RestaurantApplication class. 
       application.setRestaurantAdapter(restaurantAdapter); 
       //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call. 
       setListAdapter(restaurantAdapter); 
       //Make a webservice call in a different thread passing Keyword for URL as a string array. 
       RestaurantHttpAsyncTask m_progressTask, m_progressTask1; 
       String[] keywords = {"", "american", "asian", "italian","mexican", "chinese", "indian"}; 
       //String[] keywords = {"Chinese"}; 
       m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords); 
       m_progressTask.setRestaurantAdapter(restaurantAdapter); 
       m_progressTask.execute(); 
      } 
     } 

     if(v.getId() == goToSearch.getId()){ 

      Activity child = this; 
      while(child.getParent() != null){ 
       child = child.getParent(); 
      } 
      TabGroup1Activity parent = (TabGroup1Activity)getParent(); 


      InputMethodManager imm = (InputMethodManager)getSystemService(
        Context.INPUT_METHOD_SERVICE); 
      imm.hideSoftInputFromWindow(locationEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); 

      //changes ** restaurantAdapter to RestaurantAdapter1 to test & application to application1 
      RestaurantApplication application1 = (RestaurantApplication) this.getApplication(); 
      RestaurantAdapter restaurantAdapter1 = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label, new ArrayList<RestaurantReference>()); 
      restaurantAdapter1.setLastKnownLocation(lastKnownLocation); 
      //set a global variable for the RestaurantAdapter in the RestaurantApplication class. 
      application1.setRestaurantAdapter(restaurantAdapter1); 
      //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call. 
      setListAdapter(restaurantAdapter1); 
      //Make a webservice call in a different thread passing Keyword for URL as a string array. 
      RestaurantHttpAsyncTaskTextSearch m_progressTask, m_progressTask1; 
      String keywords = locationEditText.getText().toString(); 
      if(keywords.equals("")){ 
       keywords = "Pizza in Palo Alto"; 
      } 
      keywords = keywords.replaceAll(" ", "%20"); 
      keywords = keywords.replaceAll(",", "%20"); 
      m_progressTask = new RestaurantHttpAsyncTaskTextSearch (NearbyRestaurantActivity.this, keywords); 
      m_progressTask.setRestaurantAdapter(restaurantAdapter1); 
      m_progressTask.execute(); 

      locationEditText.setVisibility(View.GONE); 
      goToSearch.setVisibility(View.GONE); 
     } 
     if(v.getId() == searchRestaurants.getId()){ 
      if(goToSearch.isShown() == true){ 
       goToSearch.setVisibility(View.GONE); 
       locationEditText.setVisibility(View.GONE); 
      } 
      else if(goToSearch.isShown() == false){ 
       //check network connectivity before refresh 
       boolean checkConnection = isNetworkAvailable(); 
       if(!checkConnection){ 
        Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show(); 
       } 
       if(checkConnection){ 
        goToSearch.setVisibility(View.VISIBLE); 
        locationEditText.setVisibility(View.VISIBLE); 

       } 
      } 
     } 

    } 
    //Method to check network connectivity 
    public boolean isNetworkAvailable() { 
     ConnectivityManager connectivityManager 
     = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); 
     if (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting()) { 
      //Log.d("network", "Network available:true"); 
      return true; 
     } else { 
      //Log.d("network", "Network available:false"); 
      return false; 
     } 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 50, 100, this); 
     //Log.v("NearbyRestaurantActivity", "In OnResume()"); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     locManager.removeUpdates(this); 
     //Log.v("NearbyRestaurantActivity", "In onPause()"); 

    } 

    @Override 
    public void onLocationChanged(Location location) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onProviderDisabled(String provider) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onProviderEnabled(String provider) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) { 
     // TODO Auto-generated method stub 

    } 
} 






public class RestaurantHelper { 

public static double[] getLastKnownLocation(Activity activity){ 
    double lat = 0.0; 
    double lon = 0.0; 
    LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);  
    Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 

    if(location == null){ 
     lat = 0.0; 
     lon = 0.0; 
    } 
    else{ 
     //Log.v("Latitude", Double.toString(location.getLatitude())); 
     //Log.v("Longitude", Double.toString(location.getLongitude())); 

     lat = location.getLatitude(); 
     lon = location.getLongitude(); 
    } 
    return new double[]{lat,lon}; 
} 
} 
+0

Sembra che manchi del codice, che cos'è "RestaurantHelper.getLastKnownLocation (this)" e che cosa fa? Inoltre, non hai codice in "onLocationChanged()", che è dove gli aggiornamenti da locManager.requestLocationUpdates() passano in nuove posizioni. Infine, non stai visualizzando il codice OnClickListener. –

+0

Spiacente, ho aggiunto il codice per la classe RestaurantHelper. – Sia

+0

http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html (E rivedere le novità, come il fornitore di posizione fuso). –

risposta

8

Il motivo principale per cui non si è sempre aggiornato le informazioni sulla posizione in fretta è che si sta contando sul NETWORK_PROVIDER nel metodo RestaurantHelper.getLastKnownLocation(), ma la registrazione di un LocationListener per la GPS_PROVIDER in onCreate().

Quindi, questo codice in RestaurantHelper.getLastKnownLocation():

Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 

... deve essere cambiata in:

Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); 

In teoria, questo dovrebbe quindi dare l'ultima posizione GPS, che avrebbe dovuto essere aggiornato quando si registra l'ascoltatore. Al contrario, è possibile anche passare all'ascolto di NETWORK_PROVIDER in onCreate() e lasciare RestaurantHelper.getLastKnownLocation() così com'è. Dipende dal tuo requisito di precisione: se desideri che posizioni di alta precisione restituiscano la posizione più vicina al livello di edificio più vicino (ad es. 5-30 m), devi utilizzare lo GPS_PROVIDER. Ma, se riesci a vivere con una precisione grossolana, lo NETWORK_PROVIDER restituisce in genere una nuova posizione molto più veloce del GPS, soprattutto se sei in casa, e talvolta questo può essere abbastanza accurato se derivato da WiFi.

Un altro approccio sarebbe quello di ascoltare sia GPS_PROVIDER e NETWORK_PROVIDER registrando sia tramite due requestLocationUpdates() linee in onCreate(), e quindi il controllo per vedere più timestamp recente sulla Posizione da lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); e lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);, e l'utilizzo di quello che è stato aggiornato di recente .

Suggerirei anche le seguenti modifiche per rendere il codice affidabile su un gran numero di dispositivi Android:

  1. specificare il parametro requestLocationUpdates()minDistance come 0 quando si ascolta per gli aggiornamenti GPS o percorso di rete - il parametro minDistance ha una storia di essere inaffidabile e imprevedibile nel modo in cui è interpretata dagli OEM, fino ad Android 4.1.
  2. Passa al nuovo Fused Location Provider - questo dovrebbe essere molto più affidabile quando si chiama il metodo getLastKnownLocation() rispetto alle API di posizione del framework Android e più coerente su dispositivi diversi. Tieni presente che questo si basa sull'SDK di Google Play Services, disponibile solo su Android 2.2 e versioni successive.
+0

Dov'è questo fornitore di localizzazione fuso di cui parli? Il collegamento va alla documentazione Android di "Ricezione degli aggiornamenti di posizione". Nessuna menzione di alcun fornitore "Fused" lì. – Nilzor

+0

Se stai utilizzando la posizione di Google Play Services (ad esempio, ['LocationClient'] (http://developer.android.com/reference/com/google/android/gms/location/LocationClient.html), che ora è deprecato, o ['LocationServices'] (http://developer.android.com/reference/com/google/android/gms/location/LocationServices.html), stai utilizzando il provider fuso. Il provider Fused è l'unico provider disponibile tramite queste implementazioni. –

+0

Grazie per menzionare Fused Location Provider. –

5

Ho 2 consiglio per voi

  1. LocationClient video, è il nuovo modo di fare posizione roba. Ha miglioramenti rispetto al LocationManager che può essere difficile da gestire e sviluppare.

  2. Se è necessario utilizzare LocationManager, è necessario sapere che requestLocationUpdates è bacato (molto bacato). Dal momento che tutte le sue implementazioni su hardware personalizzato differiscono. C'è un trucco/soluzione che funziona. Prima di chiamare requestLocationUpdates, basta dare il via con il seguente

Codice:

HomeScreen.getLocationManager().requestLocationUpdates(
    LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() { 
     @Override 
     public void onStatusChanged(String provider, int status, Bundle extras) { 
     } 
     @Override 
     public void onProviderEnabled(String provider) { 
     } 
     @Override 
     public void onProviderDisabled(String provider) { 
     } 
     @Override 
     public void onLocationChanged(final Location location) { 
     } 
    }); 
+0

Questa cosa di kickstart non aiuta [Android Bug 57707] (https://code.google.com/p/android/issues/detail?id=57707) che riguarda almeno il provider di rete. –

+0

Basta mettere la mia risposta lì. Aspettiamo e ascoltiamo da loro. – Siddharth

2

requestLocationUpdates è bacato. Utilizzare provider di rete sempre di innescare onLocationChanged (...)

locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 100, this) 

solo dopo l'utilizzo di provider di rete fornitore di utilizzo GPS back to back:

locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 100, this) 

non dimenticate di controllare se il GPS è attivo o non prima richiesta di aggiornamento della posizione da parte di gps.

Problemi correlati