android - 从 Fragment 请求权限时,在 Activity 的 onRequestPermissionsResult 中收到不正确的 resultCode

标签 android android-fragments android-permissions android-6.0-marshmallow

我有一个 targetSdkVersion = 23, compileSdkVersion = 23 的应用程序,主要 Activity 设置如下

- HomeActivity (AppCompatActivity)
  - FragmentA (V4 Fragment)
    - ViewPager
      - NestedFragmentA (V4 Fragment)
      - NestedFragmentB (v4 Fragment)
      - NestedFragmentC (v4 Fragment)
      - NestedFragmentD (v4 Fragment)
  - Fragment B (V4 Fragment)
  - Fragment C (V4 Fragment)

在 HomeActivity 中
public static final String PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    Log.i("Logger", "Request Code: " + String.valueOf(requestCode));

    // Handle permission request result
}

我从@CommonsWare 阅读了这个答案,

https://stackoverflow.com/a/33170531/760363

嵌套 fragment 中的 onRequestPermissionsResult 永远不会被调用(在我的情况下,它的结果将返回到 HomeActivity)但我很好,我会手动通知 fragment 结果。

但问题是,当我在 HomeActivity 中请求许可时,一切正常。

首页 Activity
// Request permission from HomeActivity
// Supply 101 as request code, get 101 back

@Override
public void clickSomething(View v) {
    requestPermissions(new String[]{PERMISSION}, 101);
}

// Logcat
Logger: Request Code: 101 <<< CORRECT

但在 fragment nA 嵌套 fragment A ,当我从嵌套 fragment 请求时,返回 HomeActivity 的 requestCode 发生了变化

fragment A
// Request permission from FragmentA
// Supply 102 as request code, get 358 back

@Override
public void clickAnotherThing(View v) {
    requestPermissions(new String[]{HomeActivity.PERMISSION}, 102);
}

// Logcat
Logger: Request Code: 358 <<< INCORRECT

嵌套 fragment A
// Request permission from NestedFragmentA
// Supply 103 as request code, get 615 back

@Override
public void clickDifferentThing(View v) {
    requestPermissions(new String[]{HomeActivity.PERMISSION}, 103);
}

// Logcat
Logger: Request Code: 615 <<< INCORRECT

你知道什么会导致这个问题吗?

最佳答案

我不会否定 "Nested Fragments do not receive request permissions (onRequestPermissionsResult()) callback" 的事实。 .

但我在这里要做的是解释您观察到的关于 requestPermissions() 的容器 Activity 中收到的不同“奇怪”请求代码的行为。由 fragment 和嵌套 fragment 组成。

为了解释这一点,让我们考虑你的例子 -

- HomeActivity (AppCompatActivity)
  - FragmentA (V4 Fragment)
    - ViewPager
      - NestedFragmentA (V4 Fragment)
      - NestedFragmentB (v4 Fragment)
      - NestedFragmentC (v4 Fragment)
      - NestedFragmentD (v4 Fragment)
  - Fragment B (V4 Fragment)
  - Fragment C (V4 Fragment)

实现onRequestPermissionsResult()仅在 HomeActivity, FragmentA and NestedFragmentA为了更好地理解打印收到的请求代码的日志
    @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            Log.d("debug", "req code :: " + requestCode);     
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

还向 FragmentA 请求某些许可和 NestedFragmentA .让我们以位置权限为例
 requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 102); 

现在每当我们requestPermissions()从 fragment 或嵌套 fragment ,它调用Fragment class's requestPermissions()进而调用 FragmentHostCallback's onRequestPermissionsFromFragment()进而调用 FragmentActivity's requestPermissionsFromFragment() .现在这里是您的请求代码的转换。
验证您的请求代码后,它会调用
ActivityCompat's requestPermissions()

但是

使用转换后的请求代码 -
ActivityCompat.requestPermissions(this, permissions,((fragment.mIndex + 1) << 8) + (requestCode & 0xff));

所以更改后的请求代码是 -
((fragment.mIndex + 1) << 8) + (requestCode & 0xff)

在哪里 fragment.mIndex是 fragment 级别。所以对于直接 fragment (直接表示容器 Activity 的子项),它将是“0”
对于直接嵌套的 fragment (意味着 fragment 中的 fragment ),它将为“1”,并且它会根据 fragment 嵌套的深度而增加。

在我们的例子中,对于 FragmentA , 请求代码更改为
 (((0 + 1) << 8) + (102 & 0xff)) which computes to 358

对于 NestedFragmentA , 请求代码更改为
(((1 + 1) << 8) + (102 & 0xff)) which computes to 614

现在我们知道请求代码在哪里改变了。让我们从 ActivityCompat.requestPermissions() 继续.所以我们知道ActivityCompat.requestPermissions()因为我们使用这种方法来请求 Activity 的权限。
此外,我们知道这将执行一些操作,并且将向用户显示权限弹出窗口以接受/拒绝请求的权限。

现在我们来onRequestPermissionsResult() .当用户接受/拒绝时,onRequestPermissionsResult()的容器 Activity 将被调用,因为最终 ActivityCompat.requestPermissions()被称为。
假设您接受/拒绝来自 FragmentA 的许可所以你会得到日志-
 req code ::358

在那之后
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

将调用 FragmentActivity's onRequestPermissionsResult()依次执行一些验证和调用
frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);

低头可以看到frag.onRequestPermissionsResult()中传入的请求码是不同的。 requestCode358及之后 &0xff它变成 102再次。
瞧!
这意味着尽管我们在 358 中获得了不同的请求代码 ( HomeActivity's onRequestPermissionsResult() ) ,但我们正在调用 FragmentA's onRequestPermissionsResult()使用原始请求代码 (102)
所以我们将从 FragmentA 获取这些日志-
 req code ::358

现在来到 NestedFragmentA .假设您接受/拒绝来自 NestedFragmentA 的许可所以你会得到HomeActivity的登录-
 req code ::614

但我们知道onRequestPermissionsResult()不会为嵌套 fragment 调用,因此我们不会在 NestedFragmentA's onRequestPermissionsResult() 中获得任何日志

我想我已经解释了我们在 requestPermissions() 的容器 Activity 中获得不同请求代码的原因。由 fragment 和嵌套 fragment 组成。

所以我会说对于没有嵌套的 fragment requestPermissions()仅从 fragment 中执行 onRequestPermissionsResult()仅存在于容器 Activity 中,而不存在于容器 Activity 中。
对于嵌套 fragment ,应该 requestPermissions()仅适用于来自父 fragment 的嵌套 fragment 所需的权限。看来这是唯一的解决方法。

关于android - 从 Fragment 请求权限时,在 Activity 的 onRequestPermissionsResult 中收到不正确的 resultCode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36170324/

相关文章:

android - 如何在 MainActivity 的 onCreate 函数中获取当前的 ReactContext?

Android - 将 ProgressBar 设置为垂直条而不是水平条?

java - 如何通过按钮从另一个 fragment 选项卡打开 fragment 选项卡

android - 请求互联网许可不起作用

Android App 编译不生成包资源

android - 如何在从 fragment 打开的自定义对话框中保留监听器?

android - 在 fragment 中设置 float 操作按钮的可见性

java - 如何检查 fragment 中的权限

android - 服务可以在 Android M 中请求权限吗?

java - android:字符串值使用操作数==匹配另一个字符串值不起作用?