【问题标题】:Receive incorrect resultCode in Activity's onRequestPermissionsResult when request permission from Fragment从 Fragment 请求权限时,在 Activity 的 onRequestPermissionsResult 中收到不正确的 resultCode
【发布时间】:2016-03-23 05:13:50
【问题描述】:

我有一个应用,targetSdkVersion = 23,compileSdkVersion = 23,主要活动设置如下

- 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

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

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

HomeActivity

// 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

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

片段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

NestedFragmentA

// 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

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

【问题讨论】:

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


【解决方案1】:

我不会否认"Nested Fragments do not receive request permissions (onRequestPermissionsResult()) callback".

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

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

- 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, FragmentA and NestedFragmentA 中实现 onRequestPermissionsResult(),以便更好地理解打印收到的请求代码的日志

    @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            Log.d("debug", "req code :: " + requestCode);     
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

还向FragmentANestedFragmentA 请求某些权限。让我们以位置权限为例

 requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 102); 

现在,每当我们从片段或嵌套片段中 requestPermissions() 时,它都会调用 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 是片段级别。所以对于直接片段(直接表示容器活动的子项),它将是“0” 对于直接嵌套的片段(意味着片段中的片段),它将为“1”,并且会根据片段嵌套的深度而递增。

在我们的例子中,对于FragmentA,请求代码更改为

 (((0 + 1) << 8) + (102 & 0xff)) which computes to 358

对于NestedFragmentA,请求代码更改为

(((1 + 1) << 8) + (102 & 0xff)) which computes to 614

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

现在我们来onRequestPermissionsResult()。当用户接受/拒绝时,将调用容器活动的onRequestPermissionsResult(),因为最终调用了ActivityCompat.requestPermissions()。 假设您接受/拒绝来自FragmentA 的许可,那么您将获得日志-

 req code ::358

之后

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

将调用FragmentActivity's onRequestPermissionsResult(),然后执行一些验证并调用

frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);

你可以看到frag.onRequestPermissionsResult()中传递的请求码是不同的。 requestCode358,在 &amp;0xff 之后又变成 102。 瞧! 这意味着虽然我们在HomeActivity's onRequestPermissionsResult() 中获得了不同的请求代码(358),但我们使用原始请求代码(102)调用FragmentA's onRequestPermissionsResult() 所以我们会从FragmentA获取这些日志-

 req code ::358

现在来到NestedFragmentA。假设您接受/拒绝来自NestedFragmentA 的许可,那么您将获得登录HomeActivity -

 req code ::614

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

我想我已经解释了为什么我们在容器活动中为片段和嵌套片段生成的requestPermissions() 得到不同的请求代码的原因。

所以我会说,对于没有嵌套的片段 requestPermissions() 仅从片段中实现,并且仅在其中而不是在容器活动中实现 onRequestPermissionsResult()。 对于嵌套片段,应该requestPermissions() 仅获得来自父片段的嵌套片段所需的权限。看来这是唯一的解决方法。

【讨论】:

  • 其他问题,1.) 我可以说,如果我不覆盖 onRequestPermissionsResult 或者如果我在容器活动中调用 super,FragmentA 将收到正确的代码吗? 2.) Activity 和 ActivityCompat 的这种行为是否相同?
  • 1.是 2. ActivityCompat.requestPermissions() 反过来最终调用activity.requestPermissions()
  • 所以,没有办法解决
  • 修复方法是使用 ActivityCompat.requestPermissions(getActivity(), ... 而不是 requestPermisions(... 来源:stackoverflow.com/a/33729728/8719655
猜你喜欢
  • 2017-09-13
  • 2016-07-28
  • 1970-01-01
  • 2015-12-29
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多