Domanda

Android 4.3 su Moto G, Android 4.4.2 su Nexus 7 2012, Android 4.4.2 su Nexus 5.Android Studio 0.4.

Non voglio ricevere aggiornamenti regolari sulla posizione, voglio solo una posizione precisa quando l'utente preme un pulsante.

Ho seguito questo esempio: https://developer.android.com/training/location/retrieve-current.html

Nel file manifesto:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Verifico che i servizi di riproduzione siano disponibili utilizzando GooglePlayServicesUtil.isGooglePlayServicesAvailable

Nell'attività principale:

//in activity onCreate method
mLocationClient = new LocationClient(this, this, this);

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

//in button onclick method    
mCurrentLocation = mLocationClient.getLastLocation();

Non ho una carta SIM.Se abilito il Wifi, a volte ottengo una posizione precisa.Altre volte mCurrentLocation è nullo.

Se disabilito il Wifi, mCurrentLocation è sempre nullo.

Sto testando all'aperto in diversi luoghi sempre con una visione chiara del cielo.Ho aspettato tre minuti in ogni luogo.

Non vedo mai l'icona GPS apparire sulla barra delle notifiche di Android nella parte superiore dello schermo.

Ho queste impostazioni di posizione:enter image description here

Un'app GPS Test riesce a utilizzare con successo il GPS in ambienti chiusi sullo stesso dispositivo con Wi-Fi disabilitato in modo che il GPS funzioni:enter image description here

Registrazione per gli aggiornamenti sulla posizione, come in https://developer.android.com/training/location/receive-location-updates.html, non funziona neanche.Metodo registrato mai chiamato.

Che cosa sto facendo di sbagliato?

È stato utile?

Soluzione

L'ho risolto.Il problema era che "Consenti alle app Google di accedere alla tua posizione" era disattivato:enter image description here

Quando lo accendo ricevo le letture GPS e quando è spento no.

Lo avevo lasciato per due motivi:

  1. Sto sviluppando un'app da utilizzare su molti dispositivi di un'azienda e desidero che sia necessaria una configurazione manuale minima

  2. Lo schermo dice chiaramente "questa impostazione influisce solo sulle app di Google". So che i servizi di gioco sono software Google ma non pensavo che Google si aspettasse che un utente finale lo capisca.

Poi ho ricevuto l'aggiornamento Android 4.4.2 e la pagina delle impostazioni di posizione è cambiata.Sembra che sia possibile disattivare la Segnalazione della posizione di Google e ottenere comunque letture GPS dal provider della posizione fusa:enter image description here

Quindi forse Google si è accorto che l'impostazione era confusa e l'ha migliorata.In ogni caso, avrei risparmiato molto tempo se avessi installato la versione 4.4.2 qualche giorno fa.

Altri suggerimenti

Il problema è con getLastLocation() perché utilizza una posizione memorizzata nella cache.Ho avuto lo stesso problema di aver anche provato a usare questo semplice approccio.Dal momento che, mi sono avviato per ascoltare gli aggiornamenti (e interrompere automaticamente il 1 ° aggiornamento del 1 ° momento).

Questo è il mio codice che funziona.

In primo luogo, il controllo della disponibilità in applicazione (non essenziale, può essere in attività e senza mantenimento del risultato):

public class MainApp extends Application {
  public static enum PlayServices {
    NOT_CHECKED, AVAILABLE, UNAVAILABLE
  };
  public static PlayServices mPlayServices = PlayServices.NOT_CHECKED;

  @Override
  public void onCreate() {
    super.onCreate();

    if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
      MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;
    }
  }
}
.

Allora, acceso all'attività:

public class MainActivity extends SherlockFragmentActivity implements
  GooglePlayServicesClient.ConnectionCallbacks,
  GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
.

nel suo onCreate():

if (MainApp.mPlayServices != MainApp.PlayServices.UNAVAILABLE) {
  mLocationClient = new LocationClient(this, this, this);

  mLocationRequest = LocationRequest.create();
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
  mLocationRequest.setInterval(5000);
  mLocationRequest.setNumUpdates(1);
  mLocationRequest.setFastestInterval(1000);

  mUpdatesRequested = false;
  MainApp.prefs.edit().putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested)
      .commit();
}
.

Il resto della classe MainActivity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d(this.getClass().getSimpleName(), "onActivityResult(" + requestCode + ", " + resultCode
      + ")");
  // Decide what to do based on the original request code
  switch (requestCode) {
    case MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST:
      /*
       * If the result code is Activity.RESULT_OK, try
       * to connect again
       */
      switch (resultCode) {
        case Activity.RESULT_OK:
          // here we want to initiate location requests!
          mLocationClient = new LocationClient(this, this, this);

          break;
      }
      break;
  }
}

@Override
public void onConnected(Bundle dataBundle) {
  Log.d(this.getClass().getSimpleName(), "onConnected()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services are available.");
  MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;

  if (!mUpdatesRequested) {

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    boolean gps_enabled = false;
    try {
      gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
    }

    boolean network_enabled = false;
    try {
      network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch (Exception ex) {
    }

    // don't start listeners if no provider is enabled
    MainApp.locEnabled = gps_enabled || network_enabled;

    if (!MainApp.locEnabled) {
      // we have access to PlayServices, but user has disabled location visibility --> alert him
      alertLocationOff();
    } else {
      mLocationClient.requestLocationUpdates(mLocationRequest, this);
      mUpdatesRequested = true;
    }
  }
}

@Override
public void onDisconnected() {
  Log.d(this.getClass().getSimpleName(), "onDisconnected()");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
  Log.d(this.getClass().getSimpleName(), "onConnectionFailed()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services not available.");
  MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;

  /*
   * Google Play services can resolve some errors it detects.
   * If the error has a resolution, try sending an Intent to
   * start a Google Play services activity that can resolve
   * error.
   */
  if (connectionResult.hasResolution()) {
    try {
      // Start an Activity that tries to resolve the error
      connectionResult.startResolutionForResult(this,
          MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST);
      /*
       * Thrown if Google Play services canceled the original
       * PendingIntent
       */
    } catch (IntentSender.SendIntentException e) {
      // Log the error
      e.printStackTrace();
    }
  } else {
    /*
     * If no resolution is available, display a dialog to the
     * user with the error.
     */
    GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
  }
}

@SuppressLint("NewApi")
@Override
public void onLocationChanged(Location location) {
  Log.d(this.getClass().getSimpleName(), "onLocationChanged(), location=" + location);

  if (location != null) {
    boolean present = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
      present = Geocoder.isPresent();
    }

    if (present) {
      (new ExtractLocationTask(this)).execute(location);
    } else {
      Log.e(this.getClass().getSimpleName(), "Geocoder not present");
      MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;
    }
  }
}


private class ExtractLocationTask extends AsyncTask<Location, Void, Boolean> {
  Context mContext;

  public ExtractLocationTask(Context context) {
    super();
    mContext = context;
  }

  @Override
  protected Boolean doInBackground(Location... params) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPreExecute()");

    boolean found = false;
    try {
      Geocoder geoCoder_local = new Geocoder(mContext, Locale.getDefault());
      Geocoder geoCoder_en = new Geocoder(mContext, Locale.ENGLISH);

      List<Address> addresses_local = geoCoder_local.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);
      List<Address> addresses_en = geoCoder_en.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);

      if (addresses_local != null && addresses_local.size() > 0) {

        // do what you want with location info here

        // based on mLocationRequest.setNumUpdates(1), no need to call
        // removeLocationUpdates()

        MainApp.locEnabled = true;

        mUpdatesRequested = false;
        MainApp.prefs.edit()
            .putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested).commit();

        found = true;
      }
    } catch (IOException e) {
      Log.e(this.getClass().getSimpleName(), "Exception: ", e);
    }

    return found;
  }

  @Override
  protected void onPostExecute(Boolean found) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPostExecute()");

    if (found) {
      // update UI etc.
    } else if (!mUpdatesReRequested) {
      mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) mContext);
      mUpdatesRequested = true;
      mUpdatesReRequested = true;
    }
  }
}
.

Spero che questo ti aiuterà a farlo funzionare!

Il provider di posizione non si sveglierà il GPS fino a quando alcuni client chiedono (iscriviti) per la posizione di alta precisione (come descritto negli esempi forniti da altri utenti). L'app di test GPS non utilizza il provider di posizione ma utilizza il vecchio modo "diretto" per ottenere la posizione.

Anche c'è un meccanismo di scadenza, che rimuove le informazioni sull'ultima posizione dopo un po 'di tempo se si ritiene essere stantio.

Riassumendo tutto sopra è davvero possibile che LP (Location Provider) non abbia nulla da darti.

Penso che tu stia testando la tua applicazione in al chiuso, non funziona ..

e flusso di codice ..

public void setUpLocationClientIfNeeded() {
        createLocReq();
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(getApplicationContext(), this, // ConnectionCallbacks
                    this); // OnConnectionFailedListener
        }
    }

    private void createLocReq() {
        if (mLocationRequest == null) {
            // Create a new global location parameters object
            mLocationRequest = LocationRequest.create();
            // Set the update interval
            mLocationRequest.setInterval(LocationServices.UPDATE_INTERVAL_IN_MILLISECONDS);
            // Use high accuracy
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            // Set the interval ceiling to one minute
            mLocationRequest.setFastestInterval(LocationServices.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

            mLocationClient = new LocationClient(getApplicationContext(), this, this);
            mLocationClient.connect();
        }
    }

    public void updateLocation(Location location) {
        if (lastTrackedLat == 0.0) {
            lastTrackedLat = location.getLatitude();
        }
        if (lastTrackedLng == 0.0) {
            lastTrackedLng = location.getLongitude();
        }

        currentLat = location.getLatitude();
        currentLng = location.getLongitude();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            this.location = location;
            updateLocation(location);
        }
    }

    public Location getLocation() {
        // mLocationClient.getLastLocation();
        return location;
    }
.

Secondo i documenti

Questo metodo fornisce un modo semplificato per ottenere la posizione. È particolarmente adatto per applicazioni che non richiedono una posizione accurata e che non si desidera mantenere la logica extra per gli aggiornamenti della posizione.

Quindi può o non può restituire una posizione estremamente accurata.

GPS può richiedere un po 'per bloccare quindi chiamare getLastLocation può non restituire una posizione

Stai meglio richiedendo aggiornamenti della posizione, dopo aver ricevuto una posizione, smettere di richiedere gli aggiornamenti della posizione.

Asportando anche il codice che hai fornito, stai aspettando che il LocationClient si connetta prima di provare a ottenere una posizione?Ciò ti darà sicuramente una posizione nullo poiché non è collegata per ottenere la posizione ancora.

Cosa dovresti fare è nel tuo onConnected Ottieni l'ultima posizione lì, esempio

public void onConnected(Bundle connectionHint) {
    Location location = mLocationClient.getLastLocation();
}
.

Come dice in quell'esempio onConnected è Called by Location Services when the request to connect the client finishes successfully. At this point, you can request the current location or start periodic updates

Tutto ciò che devi fare è aggiungere una proprietà prioritaria all'oggetto di richiesta come questa.

public void onConnected(Bundle arg0)
{
    locationrequest = LocationRequest.create();
    locationrequest.setInterval(1000);
    locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationclient.requestLocationUpdates(locationrequest, this);
}
.

Forse Utilizzare una variabile booleana per consentire all'utente di avere opzioni per forzare il GPS come

boolean forceGPS=false;
.
.
.//make the user choose to change the value of the boolean
.
.
public void onConnected(Bundle arg0)
    {
        locationrequest = LocationRequest.create();
        locationrequest.setInterval(1000);
        if(forceGPS==true)
        {
        locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
        locationclient.requestLocationUpdates(locationrequest, this);
    }
.

Senza una scheda SIM Il coarse location provider non ha modo di conoscere la posizione grossolana, a meno che non sia in grado di trovare una rete WiFi che è stata mappata da Google.

Richiesta l'ultima posizione conosciuta può provocare una posizione obsoleta, e in quanto tale è piuttosto inutile.Immagino che questa sia la posizione che è stata registrata l'ultima volta che qualche app ha richiesto un aggiornamento della posizione.

Io uso il seguente codice per ottenere una posizione recente:

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    criteria.setAltitudeRequired(false);
    criteria.setSpeedRequired(false);
    criteria.setBearingRequired(false);
    criteria.setCostAllowed(false);

    final LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    ....
    LocationListener listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location lastKnownLocation) {
                     ....
        }
        // rest of interface
     }


     manager.requestSingleUpdate(criteria, listener, null);
.

L'ultima chiamata garantisce che richiediamo la posizione corrente , non la posizione in cui è stato in grado di trovare un tempo sconosciuto prima.

Potresti provare a cambiarlo su Criteria.ACCURACY_FINE per ottenere il GPS accidentato.Sii consapevole che se il GPS non avesse una soluzione per un po 'di polline, potrebbe richiedere più di diversi minuti prima che sia in realtà capace di ottenere una correzione.Mi aspetterei nel frattempo che vedresti l'icona GPS che indichi che sta aspettando una correzione.

Cosa c'è nel metodo OnConnected?

In questo metodo è necessario creare l'oggetto LocationRequest con priorità PRIORITY_HIGH_ACCURACY.

@Override
public void onConnected(Bundle dataBundle) {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationClient.requestLocationUpdates(mLocationRequest, fusedListener);
}
.

Prova questo:

public final static int MINACCURACY = 50;

private LocationManager lm;
private LocationListener listener;

private void foundLoc(double x, double y) {
    // do something with x,y
    Log.v("DEBUG", x + "," + y);
}


public void findMe(View v) {
    lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if(location.getAccuracy() < MINACCURACY) {
                foundLoc(location.getLatitude(), location.getLongitude());
                lm.removeUpdates(listener);
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, listener);
}
.

MINACCURACY è in metri.In questo modo, sul pulsante Premere (che chiama il metodo di FindMe), il GPS è abilitato, la posizione viene trovata con una precisione minima, il metodo Fooldloc ottiene i dati e il listener termina (che, a sua volta, disabilita il GPS).

.

Ci sono due cose in corso qui che ti stanno causando a volte ottenere generacoli null, e talvolta ottenere una posizione.

In primo luogo, stai creando una nuova istanza del LocationClient nel metodo onClick, che non è la stessa istanza che stai chiamando connect() su onStart(). Ciò creerà un comportamento imprevedibile in cui a volte il client avrà abbastanza tempo per connettersi prima di restituire un risultato da LocationClient.getLastLocation(), e a volte non lo farà.

Secondo, è necessario proteggere la chiamata a LocationClient.getLastLocation() con una chiamata a LocationClient.isConnected(). Dice quanto segue nei documenti LocationClient.isConnected(): https://develward.android.com /reference/com/google/android/gms/location/locationclient.html#isconnected ()

.

Controlla se il client è attualmente connesso al servizio, in modo che le richieste ad altri metodi avranno successo. Le applicazioni dovrebbero proteggere le azioni del client causato dall'utente con una chiamata a questo metodo.

Poiché l'utente attira il codice onClick() toccando il pulsante, è necessario chiamare questo metodo prima di provare a ottenere l'ultima posizione.

Allora, il tuo codice dovrebbe assomigliare a questo:

LocationClient mLocationClient;
Location mCurrentLocation;

@Override
protected void onCreate() {
    ...
    mLocationClient = new LocationClient(this, this, this);
    ...
}

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

public void onClick(View v) {
    ...
    if (mLocationClient.isConnected()) {
        // You should get a valid location here
        mCurrentLocation = mLocationClient.getLastLocation();
    }
}
.

Questo dovrebbe dare al LocationClient un tempo abbastanza lungo per connettersi e darti una posizione valida, che si spera che si vivamente includa i dati GPS.

Poiché nessuno ha condiviso questo link, ho trovato che questa è la documentazione più utile http://developer.android.com/guide/topics/location/strategies.html

"Potresti aspettarti che la correzione della posizione più recente sia la più accurata. Tuttavia, poiché la precisione di una correzione di posizione varia, la correzione più recente non è sempre la migliore. È necessario includere la logica per scegliere le correzioni di posizione in base a diversicriteri. I criteri variano anche a seconda dei casi di utilizzo dell'applicazione e dei test sul campo. "

La tua migliore scommessa è quella di mantenere un ascoltatore di localizzazione che andava finché l'attività è in primo piano e seleziona la posizione memorizzata nella cache più accurata quando viene premuto il pulsante.Potrebbe essere necessario mostrare uno spinner o qualcosa e disabilitare il pulsante mentre attende una misurazione accurata da mostrare.

Preferisco utilizzare il servizio che implementa LocationListener per ottenere la posizione attuale quasi accurata. Normalmente prendo i seguenti passaggi:

    .
  1. Inizializza LocationManager e chiama requestLocationUpdates per GPS_PROVIDER e NETWORK_PROVIDER in onCreate()
  2. Chiama getLastKnownLocation per GPS_PROVIDER e NETWORK_PROVIDER e Utilizzo getTime() per conoscere l'ultima posizione più recente.
  3. Broadcast last location (se è <30 secondi) (opzionale)
  4. Nel frattempo, quando onLocationChanged viene chiamato Confrontare la posizione recentemente aggiornata con la posizione migliore (se presente) e controllare il livello di precisione.
  5. Se accuratezza delta
  6. Broadcast Current Best Location
  7. deve rimuovere LocationManager locationManager.removeUpdates(this);
  8. call stop stels (); (È inoltre possibile interrompere il servizio da onDestroy Attività)
  9. Modifica:

    OK ... il metodo sopra il metodo stava usando l'API della posizione, di seguito ho codificato utilizzando il fornitore fuso (GooglePlayServices). Ho testato il mio Nexus 5 (Android 4.4.2), nessun sim, senza wifi ... e sto ottenendo risultati.

    Modifica 2: Ho anche testato su Android 2.3.3 LG Optimus (nessun SIM e WiFi) e ci sono voluti circa 5 minuti per ottenere il blocco (utilizzando fusibili forniti), ma stavo ricevendo un'icona di posizione all'istante.

    public class HomeActivity extends FragmentActivity implements
            ActionBar.OnNavigationListener,
            GooglePlayServicesClient.ConnectionCallbacks,
            GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
    
        private LocationClient locationClient;
        private LocationRequest locationRequest;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_home);
                // ...
                int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (resp == ConnectionResult.SUCCESS) {
                locationClient = new LocationClient(this, this, this);
                locationClient.connect();
            } else {
                Toast.makeText(this, "Google Play Service Error " + resp,
                        Toast.LENGTH_LONG).show();
    
            }
        }
    
        @Override
        public void onConnected(Bundle connectionHint) {
            if (locationClient != null && locationClient.isConnected()) {
    
                locationRequest = LocationRequest.create();
                locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
                locationRequest.setInterval(100);
                locationClient.requestLocationUpdates(locationRequest, this);
    
            }
        }
    
        @Override
        public void onLocationChanged(Location location) {
    
            try {
                if (location != null) {
                    LatLng gps = new LatLng(location.getLatitude(), location.getLongitude());
                    Log.v("JD", "My Location: " + gps.toString());
                }
            } catch (Exception e) {
                Log.d("JD",
                        "onLocationChanged", e);
    
            }       
        }
    }
    
    .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top