应用程序在从设置禁用位置权限时崩溃

时间:2018-02-01 11:04:16

标签: android geolocation location android-permissions

我有一个服务类,它在后台持续运行以获取位置更新。一切都按预期工作,但当我从设置中禁用权限时,应用程序崩溃。当我从设置中禁用位置权限时,我无法弄清楚应用程序崩溃的原因。以下是我在logcat中获得的内容。

FATAL EXCEPTION: GoogleApiHandler
                 Process: com.android.myapp, PID: 7703
                 java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any location operations.
                 at android.os.Parcel.readException(Parcel.java:1683)
                 at android.os.Parcel.readException(Parcel.java:1636)
                 at com.google.android.gms.internal.zzeu.zza(Unknown Source)
                 at com.google.android.gms.internal.zzcfa.zzif(Unknown Source)
                 at com.google.android.gms.internal.zzcfd.getLastLocation(Unknown Source)
                 at com.google.android.gms.internal.zzcfk.getLastLocation(Unknown Source)
                 at com.google.android.gms.location.zzg.zza(Unknown Source)
                 at com.google.android.gms.common.api.internal.zze.zza(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.zzb(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.zzaiw(Unknown Source)
                 at com.google.android.gms.common.api.internal.zzbo.onConnected(Unknown Source)
                 at com.google.android.gms.common.internal.zzac.onConnected(Unknown Source)
                 at com.google.android.gms.common.internal.zzn.zzakr(Unknown Source)
                 at com.google.android.gms.common.internal.zze.zzw(Unknown Source)
                 at com.google.android.gms.common.internal.zzi.zzaks(Unknown Source)
                 at com.google.android.gms.common.internal.zzh.handleMessage(Unknown Source)
                 at android.os.Handler.dispatchMessage(Handler.java:102)
                 at android.os.Looper.loop(Looper.java:154)
                 at android.os.HandlerThread.run(HandlerThread.java:61)

这是我的服务类。这总是在后台运行。

public class LocationService extends Service {


    ...
    ...
    ...

    @Override
    public void onCreate() {
        try {
            mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

            mLocationCallback = new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    super.onLocationResult(locationResult);
                    onNewLocation(locationResult.getLastLocation());
                }
            };

            createLocationRequest();
            getLastLocation();
            requestLocationUpdates();
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "Service started");

        return START_STICKY;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public void onDestroy() {
        Log.i(TAG, "Service destroy");
        Toast.makeText(getApplicationContext(), "Service Destroy", Toast.LENGTH_SHORT).show();
    }

    /**
     * Makes a request for location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void requestLocationUpdates() {
        Log.i(TAG, "Requesting location updates");
        Utils.setRequestingLocationUpdates(this, true);
        try {

          mFusedLocationClient.requestLocationUpdates(mLocationRequest,
                mLocationCallback, Looper.myLooper());
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, false);
            Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
        }
    }

    /**
     * Removes location updates. Note that in this sample we merely log the
     * {@link SecurityException}.
     */
    public void removeLocationUpdates() {
        Log.i(TAG, "Removing location updates");
        try {

   mFusedLocationClient.removeLocationUpdates(mLocationCallback);
            Utils.setRequestingLocationUpdates(this, false);
            stopSelf();
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, true);
            Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
        }
    }

    private void getLastLocation() {
        try {
            mFusedLocationClient.getLastLocation()
                .addOnCompleteListener(task -> {
                        if (task.isSuccessful() && task.getResult() != null) {
                            mLocation = task.getResult();
                        } else {
                            Log.w(TAG, "Failed to get location.");
                        }
                    });
        } catch (SecurityException unlikely) {
            Log.e(TAG, "Lost location permission." + unlikely);
        }
    }

    private void onNewLocation(Location location) {
        Log.i(TAG, "New location: " + location);

        mLocation = location;
        // Doing some operations using location data.
        mPreviousLocation = mLocation;
        System.gc();

    }

    /**
     * Sets the location request parameters.
     */
    private void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest
         .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest
        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.i(TAG, "Service Task Removed");
        Toast.makeText(getApplicationContext(), "Service Task Removed", Toast.LENGTH_SHORT).show();
        startService(new Intent(getApplicationContext(), LocationService.class));
        super.onTaskRemoved(rootIntent);
    }
}

我正在检查活动类中的位置权限,并在用户接受权限后启动服务。没有问题,我甚至从后台服务获得位置更新。同时,当我尝试从设置中禁用权限时,应用程序崩溃。这是我的MainActivity类,我正在检查位置权限。

public class MainActivity extends AppCompatActivity{


@Override
protected void onResume() {
    super.onResume();
    checkAndEnableGps();
}

private void checkAndEnableGps() {
    try {
        new RxPermissions(this)
                .request(Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(granted -> {
                    if (granted) {
                        if (!Utils.isServiceRunning(this, LocationService.class)) {
                            startService(new Intent(this, LocationService.class));
                        }
                        showSettingDialog();
                    } 
                });

    }catch (Exception e){
        e.printStackTrace();
    }
}

}

5 个答案:

答案 0 :(得分:1)

您收到有关用户拒绝的位置访问权限的错误,您需要使用checkSelfPermission(context,permission)方法检查授予的权限,这将返回权限授予状态,然后您可以请求权限访问权限用户。

%~I                     Expands %I which removes any surrounding 
                    quotation marks ("").
%~fI                    Expands %I to a fully qualified path name.
%~dI                    Expands %I to a drive letter only.
%~pI                    Expands %I to a path only.
%~nI                    Expands %I to a file name only.
%~xI                    Expands %I to a file extension only.
%~sI                    Expands path to contain short names only.
%~aI                    Expands %I to the file attributes of file.
%~tI                    Expands %I to the date and time of file.
%~zI                    Expands %I to the size of file.
%~$PATH:I               Searches the directories listed in the PATH environment 
                    variable and expands %I to the fully qualified name of 
                    the first one found. If the environment variable name 

然后从您请求权限的上下文中使用'onRequestPermissionsResult'回调,并在授予权限后启动您的位置服务。

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
    mMap.setMyLocationEnabled(true);
} else {
    // Show rationale and request permission.
}

请参阅https://developers.google.com/maps/documentation/android-api/location以获取文档。

答案 1 :(得分:0)

你必须为6+添加checkpermission,例如下面的Marshmallow,

public void checkPermission()
{
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                   ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
    {

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
                    123);
    }
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) {
    checkPermission();
}

希望它有所帮助!

答案 2 :(得分:0)

它需要这些权限,你删除它们,所以当它试图获取它崩溃的位置时。

使用catch语句来处理异常或检查你是否有权限并在实际尝试获取位置之前要求它们运行时

答案 3 :(得分:0)

在运行服务之前,请检查您是否有权限。

mContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED;

如果您没有权限,可以从FragmentActivity申请。

requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION }, 200 /*request code*/);

您可以在FragmentActivity课程中获得用户响应,即 PERMISSION_GRANTED

@Override
public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions, @NonNull int[] grantResults){

    switch(permsRequestCode){

        case 200:    // notice the request code is the same as requested.

            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                startService();
            }
            else {
                // don't start service.
            }

            break;
    }
}

答案 4 :(得分:0)

这种情况正在发生,因为自API版本6.0起,您需要在运行时检查权限。如果未授予权限,您的应用应在执行权限相关任务之前要求授予权限。

此处,对于访问用户位置,所需权限为ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION。因此,您需要检查用户是否授予了位置权限。

还有一件事,你在服务类中占据一席之地。这是一个问题 -

  

您不能要求用户获得服务许可

但您可以通过致电checkSelfPermission()

进行检查

为了使它更好,您应该在Activity / Fragment类中检查并请求权限,然后手动启动服务。

另一方面,您可以检查服务中的权限,如果用户不接受,则显示通知,授予权限,然后启动服务。

您已经在活动中检查了许可

因此,现在使用checkSelfPermission()来检查用户是否授予了权限。如果没有,则显示Notification with PendingIntent添加一些标记。打开活动请求权限,然后启动服务,

startService(new Intent(YourActivity.this, YourService.class));