Android Marshmallow:在运行时更改权限会使应用程序崩溃

Posted

技术标签:

【中文标题】Android Marshmallow:在运行时更改权限会使应用程序崩溃【英文标题】:Android Marshmallow: Changing permissions at run time crashes app 【发布时间】:2016-09-06 17:26:19 【问题描述】:

Marshmallow 重新设计了获取权限。所以在调用需要权限的方法之前处理权限并且它工作正常,但它在以下情况下崩溃:

第 1 步:打开应用并授予所有必要的权限

第 2 步:单击主页按钮(因此应用程序在后台)

第 3 步:在设置中手动更改权限

第 4 步:从多任务启动应用程序,现在由于应用程序上下文无效而崩溃

观察到应用程序再次创建,不明白为什么会发生这种情况。欢迎提出任何纠正此问题的建议!

【问题讨论】:

有异常吗??如果是,你应该在 try catch 块中处理它 检查这个....***.com/questions/33488589/… 发现了这个问题,因为当我们通过保持应用程序在后台运行来动态更改权限时,应用程序被重新创建,我用来访问共享首选项的上下文变为空 【参考方案1】:

首先定义一个布尔值

 private boolean isPermissionGranted = false;

然后检查是否授予权限:

if (!isPermissionGranted) 
        checkPermission();
    

运行时权限检查的实际代码如下:

private void checkPermission() 
    int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA);
    int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) 
        if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) 
            showMessage(getString(R.string.allow_access_to_camera_external_storage),
                    new DialogInterface.OnClickListener() 
                        @Override
                        public void onClick(DialogInterface dialog, int which) 
                            ActivityCompat.requestPermissions(UserProfile.this, new String[]Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        
                    );
            return;
        
        ActivityCompat.requestPermissions(UserProfile.this, new String[]Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
     else 
        isPermissionGranted = true;
    


private void showMessage(String message, DialogInterface.OnClickListener       listener) 
    new AlertDialog.Builder(UserProfile.this)
            .setMessage(message)
            .setPositiveButton(R.string.ok, listener)
            .setNegativeButton(R.string.cancel, null)
            .create()
            .show();


  @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
    switch (requestCode) 
        case REQUEST_CODE_ASK_PERMISSIONS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                isPermissionGranted = true;

             else 
                isPermissionGranted = false;
                Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT)
                        .show();
            
            break;

        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    

您可以参考上面的代码并在您的应用程序中实现它。

【讨论】:

【参考方案2】:

观察到应用再次创建,不明白为什么会这样 发生。欢迎提出任何纠正此问题的建议!

因为当权限改变时,应用“状态”应该失效。正确的做法是销毁根上下文,即应用程序本身。

每次查询需要这些权限的 API 方法时,都必须检查权限授予状态。您不能依赖某些 SharedPreferences 标志来表示“用户授予了入职权限,好的,让我们玩得开心”。在这方面使您的应用程序无状态。

例如,您可以创建一些 BaseActivity/BaseFragment 或 Utility 并将所有检查逻辑移入其中。

【讨论】:

【参考方案3】:

这是因为 Marshmallow 添加了其他功能。您需要在运行时向用户请求。为此,请使用我制作的此类。然后在需要的地方使用它

public class AppPermission 

    public static boolean isMarshmallowPlusDevice() 
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    

    @TargetApi(Build.VERSION_CODES.M)
    public static boolean isPermissionRequestRequired(Activity activity, @NonNull String[] permissions, int requestCode) 
        if (isMarshmallowPlusDevice() && permissions.length > 0) 
            List<String> newPermissionList = new ArrayList<>();
            for (String permission : permissions) 
                if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) 
                    newPermissionList.add(permission);
                
            
            if (newPermissionList.size() > 0) 
                activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode);
                return true;
            
        
        return false;
    

然后将此代码放在需要用户许可的地方。

if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]"android.permission.GET_ACCOUNTS",
        REQUEST_APP_PERMISSION)) 
    // Your code if permission available

在此之后,在您的FragmentActivity 中输入此代码-

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) 
        case REQUEST_APP_PERMISSION:
            for (int i = 0; i < permissions.length; i++) 
                String permission = permissions[i];
                int grantResult = grantResults[i];
                switch (permission) 
                    case "android.permission.GET_ACCOUNTS":
                        if (PackageManager.PERMISSION_GRANTED == grantResult) 
                            // Your code
                        
                        break;
                
            
            break;
    

以上代码用于GET_ACCOUNTS的请求权限,您可以将其更改为所需的任何内容。

【讨论】:

如果上面的代码还不够,那就放一些代码。上面的代码大部分都错过了 我面临的不是代码级问题,只是想确保在我手动更改设置中的权限时重新创建应用程序(在启动在后台运行的应用程序时,它会崩溃) @ABI : 你的问题解决了吗?恢复应用时如何处理异常。

以上是关于Android Marshmallow:在运行时更改权限会使应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Android Marshmallow:在运行时更改权限会使应用程序崩溃

永远不会结束marshmallow android的后台服务

可以在 Android Marshmallow (API 23) 的运行时权限模型中同步请求权限吗?

如何在 Android 6.0 Marshmallow 中访问相机?

Android Marshmallow:使用 Espresso 测试权限?

错误:无法连接到相机服务@Android marshmallow