2015-09-10 19 views
71

Sto cercando di ottenere le coordinate GPS da visualizzare quando faccio clic su un pulsante nel mio layout di attività. Quanto segue è il metodo che viene chiamato quando si fa clic sul pulsante:Controllo permesso Android per LocationManager

public void getLocation(View view) { 
    TextView tv = (TextView) findViewById(R.id.gps_coord_view); 
    LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE); 
    Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
    tv.setText("Latitude: " + loc.getLatitude() + "\nLongitude: " + loc.getLongitude()); 
} 

Ricevo un errore che dice

chiamata richiede l'autorizzazione che può essere rifiutata dall'utente. Il codice dovrebbe verificare esplicitamente se è disponibile l'autorizzazione.

Ho già concesso queste autorizzazioni nel mio AndroidManifest. L'errore è curato e l'applicazione compila quando aggiungo quanto segue prima di chiamare lm.getLastKnownLocation:

if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED 
     && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
    return; 
} 

Tuttavia, l'applicazione si blocca quando si preme il pulsante che chiama getLocation quando viene cliccato. Cosa sta succedendo? C'è un modo migliore/più semplice per afferrare le coordinate GPS del dispositivo?

+0

Probabilmente è possibile allegare un registro delle eccezioni. – Milan

+1

Usa ContextCompat.checkSelfPermission (contesto, autorizzazione) e assicurati di aver menzionato le autorizzazioni appropriate nel manifest –

risposta

113

Con il livello API Android (23), è necessario verificare le autorizzazioni. https://developer.android.com/training/permissions/requesting.html

ho avuto il tuo stesso problema, ma le seguenti funzionato per me e io sono in grado di recuperare Località dati con successo:

(1) Assicurarsi di aver le autorizzazioni elencati nel manifesto:

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

(2) Assicurarsi di richiedere i permessi da parte dell'utente:

if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 

      ActivityCompat.requestPermissions(this, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION }, 
               LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION); 
     } 

(3) Assicurarsi di utilizzare ContextCompat come questo ha compatibilità con i vecchi livelli API.

(4) Nel vostro servizio di localizzazione o una classe che inizializza il vostro LocationManager e ottiene l'ultima posizione nota, abbiamo bisogno di controllare le autorizzazioni:

if (Build.VERSION.SDK_INT >= 23 && 
      ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && 
      ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      return ; 
     } 

(5) Questo approccio ha funzionato solo per me dopo che ho incluso @TargetApi (23) nella parte superiore del mio metodo initLocationService.

(6) Ho anche aggiunto questo al mio accumulo Gradle:

compile 'com.android.support:support-v4:23.0.1' 

Ecco la mia LocationService per riferimento:

public class LocationService implements LocationListener { 

    //The minimum distance to change updates in meters 
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters 

    //The minimum time between updates in milliseconds 
    private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute 

    private final static boolean forceNetwork = false; 

    private static LocationService instance = null; 

    private LocationManager locationManager; 
    public Location location; 
    public double longitude; 
    public double latitude; 


    /** 
    * Singleton implementation 
    * @return 
    */ 
    public static LocationService getLocationManager(Context context)  { 
     if (instance == null) { 
      instance = new LocationService(context); 
     } 
     return instance; 
    } 

    /** 
    * Local constructor 
    */ 
    private LocationService(Context context)  { 

     initLocationService(context); 
     LogService.log("LocationService created"); 
    } 



    /** 
    * Sets up location service after permissions is granted 
    */ 
    @TargetApi(23) 
    private void initLocationService(Context context) { 


     if (Build.VERSION.SDK_INT >= 23 && 
      ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && 
      ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
      return ; 
     } 

     try { 
      this.longitude = 0.0; 
      this.latitude = 0.0; 
      this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 

      // Get GPS and network status 
      this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
      this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 

      if (forceNetwork) isGPSEnabled = false; 

      if (!isNetworkEnabled && !isGPSEnabled) { 
       // cannot get location 
       this.locationServiceAvailable = false; 
      } 
      //else 
      { 
       this.locationServiceAvailable = true; 

       if (isNetworkEnabled) { 
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 
          MIN_TIME_BW_UPDATES, 
          MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 
        if (locationManager != null) { 
         location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
         updateCoordinates(); 
        } 
       }//end if 

       if (isGPSEnabled) { 
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 
          MIN_TIME_BW_UPDATES, 
          MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 

        if (locationManager != null) { 
         location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
         updateCoordinates(); 
        } 
       } 
      } 
     } catch (Exception ex) { 
      LogService.log("Error creating location service: " + ex.getMessage()); 

     } 
    }  


    @Override 
    public void onLocationChanged(Location location)  { 
     // do stuff here with location object 
    } 
} 

ho provato con un dispositivo Android Lollipop finora solo. Spero che questo funzioni per voi.

+2

Mi piace la tua soluzione, ma dovresti controllare se locationManager è nullo prima di usarlo, non più tardi. – Fer

+0

Ottengo "java.lang.NullPointerException: tentativo di leggere dal campo 'double android.location.Location.mLatitude' su un riferimento oggetto nullo" se non controllo i valori null al momento –

+0

Voglio dire che dovresti controllare "se (locationManager! = null) "subito dopo" if (isNetworkEnabled) "e subito dopo" if (isGPSEnabled) {"sebbene non sia realmente necessario: non può essere nullo su quella riga perché lo hai usato in precedenza nella riga" questo .isGPSEnabled = locationManager.isProviderEnabled (LocationManager.GPS_PROVIDER); " e il suo valore non cambierà in null nel tuo codice. – Fer

36

L'ultima parte del messaggio di errore che hai citato afferma: ...with ("checkPermission") or explicitly handle a potential "SecurityException"

A molto più veloce/modo più semplice di controllare se si dispone delle autorizzazioni è quello di circondare il codice con try { ... } catch (SecurityException e) { [insert error handling code here] }. Se hai i permessi, la parte 'try' verrà eseguita, se non lo fai, la parte 'catch' lo farà.

+1

Utile se non si dispone di un oggetto Attività o contesto per cui è possibile verificare le autorizzazioni. – Nublodeveloper

35

soluzione semplice

ho voluto supportare applicazioni pre api 23 e invece di usare checkSelfPermission Ho usato un try/catch

try { 
    location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 
} catch (SecurityException e) { 
    dialogGPS(this.getContext()); // lets the user know there is a problem with the gps 
} 
4

se si sta lavorando sulle autorizzazioni dinamici e alcun permesso, come ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION dando errore "impossibile risolvere il metodo PERMISSION_NAME" in questo caso scrivi il tuo codice con il nome del permesso e poi ricostruisci il tuo progetto questo rigenererà il file manifest (Manifest.permission).

Problemi correlati