android - verificare - smartphone con migliore ricezione gps




Il fornitore di localizzazione fuso non sembra utilizzare il ricevitore GPS (8)

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 desidero 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 manifest:

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

Controllo che i Servizi di gioco siano disponibili utilizzando GooglePlayServicesUtil.isGooglePlayServicesDisponibili

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 carta SIM. Se abilito il Wifi, a volte ottengo una posizione precisa. Altre volte mCurrentLocation è null.

Se disattivo Wifi, mCurrentLocation è sempre nullo.

Sto testando fuori in diverse posizioni sempre con una chiara visione del cielo. Ho aspettato tre minuti in ogni luogo.

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

Ho queste impostazioni di posizione:

Un'app GPS Test riesce a utilizzare il GPS con successo all'interno dello stesso dispositivo con Wi-Fi disabilitato in modo che il GPS funzioni:

Anche la registrazione per gli aggiornamenti di posizione, come in https://developer.android.com/training/location/receive-location-updates.html , non funziona. Metodo registrato mai chiamato.

Che cosa sto facendo di sbagliato?


Ci sono due cose che stanno causando a volte di ottenere null , e talvolta ottenere una posizione.

Innanzitutto, stai creando una nuova istanza di LocationClient nel metodo onClick , che non è la stessa istanza che stai chiamando connect() su onStart() . Ciò creerà comportamenti imprevedibili laddove a volte il client avrà abbastanza tempo per connettersi prima di restituire un risultato da LocationClient.getLastLocation() , e talvolta non lo farà.

In secondo luogo, dovresti proteggere la chiamata a LocationClient.getLastLocation() con una chiamata a LocationClient.isConnected() . Dice quanto segue nei documenti LocationClient.isConnected() : https://developer.android.com/reference/com/google/android/gms/location/LocationClient.html#isConnected()

Verifica se il client è attualmente connesso al servizio, in modo che le richieste ad altri metodi abbiano esito positivo. Le applicazioni devono proteggere le azioni dei client causate dall'utente con una chiamata a questo metodo.

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

Quindi, 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 sufficiente per connettersi e darti una posizione valida, che dovrebbe includere i dati GPS.


Cosa c'è nel metodo OnConnected ?

In questo metodo devi 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);
}

Il problema è con getLastLocation() perché utilizza un percorso memorizzato nella cache. Ho avuto lo stesso problema che ho provato anche a usare questo approccio semplice. Da allora, sono passato ad ascoltare gli aggiornamenti (e mi sono fermato dopo il 1 ° aggiornamento di successo automaticamente).

Questo è il mio codice che funziona.

Innanzitutto, il controllo della disponibilità in Applicazione (non essenziale, può essere in Attività e senza tenere conto 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;
    }
  }
}

Quindi, fino 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 aiuti a farlo funzionare!


Il provider di localizzazione non attiva il GPS finché alcuni clienti non chiedono (sottoscrivi) una 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" di ottenere la posizione.

Inoltre, esiste un meccanismo di scadenza che rimuove le informazioni sull'ultima posizione dopo un po 'di tempo se si ritiene che sia obsoleto.

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


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

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

Preferisco utilizzare il servizio che implementa LocationListener per ottenere l'attuale posizione quasi accurata. Di solito faccio 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 utilizza getTime() per conoscere l'ultima posizione più recente.
  3. Trasmetti l'ultima posizione (se è <30 sec vecchio) (opzionale)
  4. Nel frattempo, quando viene chiamato onLocationChanged confronto la posizione appena aggiornata con l'ultima posizione migliore (se presente) e controllo il livello di precisione.
  5. Se il delta di precisione <MIN_ACCURACY (variabile utente), utilizzarlo come posizione migliore
  6. Trasmetti la migliore posizione corrente
  7. È necessario rimuovere LocationManager locationManager.removeUpdates(this);
  8. Chiama stopSelf (); (puoi anche interrompere il servizio dall'attività onDestroy )

MODIFICARE:

OK ... Il metodo di cui sopra utilizzava API di localizzazione, di seguito ho codificato utilizzando Fused Provider (GooglePlayServices). Ho provato il mio Nexus 5 (Android 4.4.2), NESSUN SIM, NO WIFI ... e sto ottenendo risultati.

Modifica 2: Ho anche provato su Android 2.3.3 LG Optimus (No SIM e Wifi) e ci sono voluti circa 5 minuti per ottenere il blocco (utilizzando Fused fornito), ma stavo ottenendo l'icona della 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);

        }       
    }
}

Secondo i documenti

Questo metodo fornisce un modo semplificato per ottenere la posizione. È particolarmente adatto per applicazioni che non richiedono una posizione precisa e che non desiderano mantenere una logica aggiuntiva per gli aggiornamenti di posizione.

quindi può o non può restituire una posizione altamente precisa.

Il GPS può richiedere un po 'di tempo per bloccarsi, quindi chiamare getLastLocation può o meno restituire una posizione

è meglio richiedere gli aggiornamenti di posizione, quindi dopo aver ottenuto una posizione basta interrompere la richiesta di aggiornamenti di posizione.

Anche guardando il codice che hai fornito stai aspettando che il LocationClient connetta prima di provare a ottenere una posizione? Questo ti darà sicuramente una posizione nullo poiché non è ancora connesso per ottenere la posizione.

quello che dovresti fare è nel tuo onConnected ottenere l'ultima posizione lì, ad esempio

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

come si 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 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


Senza una carta SIM, il coarse location provider non ha modo di conoscere la posizione approssimativa, a meno che non sia in grado di trovare una rete WiFi mappata da Google.

Richiedere l'ultima posizione nota può comportare una posizione obsoleta e, in quanto tale, è piuttosto inutile. Immagino che questa sia la posizione che è stata registrata l'ultima volta che alcune app hanno 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 chiediamo la posizione corrente , non la posizione in cui è stata in grado di trovare una quantità sconosciuta di tempo prima.

Potresti provare a cambiarlo in Criteria.ACCURACY_FINE per attivare il GPS. Essere consapevoli del fatto che se il GPS non ha avuto una correzione per un po 'di tempo potrebbe richiedere più di alcuni minuti prima che sia effettivamente in grado di ottenere una correzione. Mi aspetterei nel frattempo che vedresti l'icona GPS che indica che è in attesa di una correzione.







google-play-services