【问题标题】:Marshmallow and above Permissions : Runtime CrashMarshmallow 及以上权限:运行时崩溃
【发布时间】:2018-05-08 10:24:15
【问题描述】:

我的运行时权限有问题,我尝试为 Marshmallow 及更高版本管理它们,但我的应用程序仍然在运行时崩溃(不是在我重新启动应用程序时) 这是活动代码:

在清单中:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

这里是活动代码(我认为不是全部,但必须理解)

 public class HomeActivityNew extends AppCompatActivity implements AdapterView.OnItemClickListener, View.OnClickListener, SeekBar.OnSeekBarChangeListener {

    // here all variables ...
        private boolean permissionToRecordAccepted = false;
        private boolean permissionToWriteAccepted = false;
        private String[] permissions = {"android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"}


       @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_home_new);

            int requestCode = 200;
            if (Build.VERSION.SDK_INT >= 23) {
                requestPermissions(permissions, requestCode);
            }

            init();
            myHandler = new Handler();
            slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.HIDDEN);
            SetupToolbar();
            SetupPager();
            SetupDrawer();
            iv_playpause.setTag("pause");



            MobileAds.initialize(getApplicationContext(), getResources().getString(R.string.admov_id));
            AdView mAdView = (AdView) findViewById(R.id.adView);
            AdRequest adRequest = new AdRequest.Builder().build();
            mAdView.loadAd(adRequest);


          /*  SharedPreferences pref = getSharedPreferences("logincheck", Context.MODE_PRIVATE);
            SharedPreferences.Editor edit1 = pref.edit();
            edit1.putString("login","true");
            edit1.apply();*/

        }


        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            switch (requestCode) {
                case 200:
                    if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                        permissionToRecordAccepted=true;
                    }
                    if(grantResults.length > 0 && grantResults[1] == PackageManager.PERMISSION_GRANTED){
                        permissionToWriteAccepted=true;
                    }

                    break;
            }
            if (!permissionToRecordAccepted) HomeActivityNew.super.finish();
            if (!permissionToWriteAccepted) HomeActivityNew.super.finish();
        }

这是错误:

java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=200, result=0, data=null} to activity {com.mypackage.HomeActivityNew}: java.lang.

Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0

变量grantResults 为空! 运行时的应用程序显示权限对话框窗口并同时崩溃,但是当我重新启动应用程序时,它会等待权限

【问题讨论】:

标签: android indexoutofboundsexception android-permissions


【解决方案1】:

这样写

private String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE}

插入

private String[] permissions = {"android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"}

【讨论】:

  • 谢谢@SahdevRajput,但我试过了,我得到了同样的结果,奇怪的是第一次启动时崩溃但关闭后我重新打开应用程序并显示权限对话框并等待!
  • 错误是包含权限结果的:grantResults 是空的,所以它关闭了应用程序,正如我在代码中提到的那样:if (!permissionToRecordAccepted) HomeActivityNew.super.finish(); if (!permissionToWriteAccepted) HomeActivityNew.super.finish();
  • 我没有错误,它唯一的应用程序不检查权限,当我尝试记录 grantResults[0] 进行测试时,我只收到错误(我上面写的错误),因为 grantResults 是空的我不知道为什么手机没有获得权限并在 1 毫秒内关闭对话框:java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=200, result=0, data=null} to activity {com.mypackage.HomeActivityNew}: java.lang. Caused by: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
【解决方案2】:

在您使用的代码中

if (Build.VERSION.SDK_INT >= 23) {
  requestPermissions(permissions, requestCode);//Call require API level 23 and above          
} 

所以你没有提到其他情况,你应该请求 API 级别 23 或低级别的权限。所以更正了代码:

 if(Build.VERSION.SDK_INT > Build.VERSION_CODES.M){
     //Call this method for API level 21 and above
  requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},200);
    }else{
      ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECORD_AUDIO},200);
     }

【讨论】:

  • 我认为执行 case '>= 23' 是合乎逻辑的,因为 else 已经在 Manifest 中(并且用户在从 Playstore 安装应用程序之前接受),不是吗?
  • 在这种情况下,如果您想过滤掉 API 级别 23 及更高级别的应用,请设置 android:minSdkVersion=23。请阅读这篇文章link
  • 它现在不是问题,但我也添加了它,因为我用三星 S7 (API 24) 测试我应该是SDK_INT &gt;Build.VERSION_CODE.M 我真的不明白为什么:权限对话框不待到准许或拒绝准许为止。重新启动后,它们仍然存在。很奇怪
【解决方案3】:

this.requestPermissions 不应在 onCreate 中调用。 documentation on requestPermission 声明:

此方法可以启动一个活动,允许用户选择授予哪些权限以及拒绝哪些权限。因此,您应该准备好您的活动可能会暂停和恢复。此外,授予某些权限可能需要重新启动您的应用程序。在这种情况下,系统将在将结果传递给 onRequestPermissionsResult(int, String[], int[]) 之前重新创建活动堆栈。

当检查你是否有权限时,你应该使用 checkSelfPermission(String)。

调用此 API 以获得已授予您的应用的权限会向用户显示 UI,以决定该应用是否仍可持有这些权限。如果您的应用使用由权限保护的数据的方式发生重大变化,这将很有用。

这些陈述暗示requestPermissions 依赖于活动生命周期。因此,您的活动需要能够处理暂停和恢复,甚至在请求权限时触发重新启动。因此,请等到您的活动完全设置好(稍后在 onCreate 或稍后的回调中调用 requestPermissions)。

更好的是,您正在接近这个错误。根据Android Documentation - Requesting Permissions

注意:从 Android 6.0(API 级别 23)开始,用户可以随时撤消任何应用的权限,即使该应用的目标 API 级别较低。 无论您的应用所针对的 API 级别如何,您都应该测试您的应用以验证其在缺少所需权限时是否能正常运行

(强调我的)。

如果您因为缺少权限而终止您的活动,那么您正在创造糟糕的用户体验。即时应用程序关闭并且没有给出任何理由至少可以说是令人困惑的。而且,即使它确实授予了权限,用户也可以随时撤销它们。

您应该调用AppCompat.requestPermissions(thisActivity, permissions, requestCode),并且您应该onCreate(活动未完全初始化)中调用它。

此外,只有在您的应用尚未授予权限时,您才应该调用它。所以你应该在你的应用需要权限时调用ActivityCompat.checkSelfPermission

如果做不到这一点,它应该请求它需要的权限。这样做时,它应该检查是否应该显示基本原理(当用户过去拒绝许可或在某个时候撤销许可时)。这是googlesamples/android-runtime-permissions的摘录

private void requestCameraPermission() {
    Log.i(TAG, "CAMERA permission has NOT been granted. Requesting permission.");

    // BEGIN_INCLUDE(camera_permission_request)
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.CAMERA)) {
        // Provide an additional rationale to the user if the permission was not granted
        // and the user would benefit from additional context for the use of the permission.
        // For example if the user has previously denied the permission.
        Log.i(TAG,
                "Displaying camera permission rationale to provide additional context.");
        Snackbar.make(mLayout, R.string.permission_camera_rationale,
                Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.ok, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CAMERA},
                                REQUEST_CAMERA);
                    }
                })
                .show();
    } else {

        // Camera permission has not been granted yet. Request it directly.
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
                REQUEST_CAMERA);
    }
    // END_INCLUDE(camera_permission_request)
}

请参阅示例的其余部分(上一行),了解请求权限通常是如何完成的。还有其他方法可以编写代码来获得其他行为,但您应该首先从一个经过验证且有效的示例开始,并了解每次调用的原因,然后再转向新的方向。

(Developer Samples - Runtime Permissions 是上面示例的 v7 重新实现。我建议您查看两者以了解权限的工作原理。但请注意,不要进行不兼容的 v4 和 v7 调用,这可能会导致令人沮丧的错误)

让我再次强调:用户可以随时撤销权限,即使平台/sdk 低于 api 23。因此,您必须在需要权限时检查权限。

【讨论】:

  • 我这样做了,但 grantResults 保持为空,应用程序快速关闭权限窗口,就像我删除这些行时我没有请求权限一样:
    //if (!permissionToRecordAccepted) HomeActivityNew.super.finish(); //if (!permissionToWriteAccepted) HomeActivityNew.super.finish(); 应用程序保持打开状态,但它没有在没有这些权限的情况下继续合法
  • 完全重写了我的答案。看看这个新答案是否有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
相关资源
最近更新 更多