当Fragment的请求权限时,在Activity的onRequestPermissionsResult中接收到错误的resultCode

时间:2016-03-23 05:13:50

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

我有一个带有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

但是在 FragmetnA NestedFragmentA 中,当我从嵌套片段请求时,返回HomeActivity的requestCode已更改

FragmentA

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

您是否知道会导致此问题的原因?

1 个答案:

答案 0 :(得分:14)

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

这一事实

但我在这里要做的是解释你所观察到的关于不同的&#34;怪异的&#34;在片段和嵌套片段的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)

仅在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);
    }

同时请求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)

<强> BUT

使用转换后的请求代码 -

fragment.mIndex

因此更改的请求代码为 -

FragmentA

其中 (((0 + 1) << 8) + (102 & 0xff)) which computes to 358 是片段级别。因此,对于立即片段(直接意味着容器活动的子代),它将是&#34; 0&#34; 对于直接嵌套的片段(意味着片段内的片段),它将是&#34; 1&#34;并且它会根据你的片段嵌套的深度而增加。

在我们的案例中,对于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(),然后执行一些验证并调用

requestCode

Bow,您可以看到358中传递的请求代码不同。 &0xff102358之后又为HomeActivity's onRequestPermissionsResult()。  瞧!! 这意味着虽然我们在FragmentA's onRequestPermissionsResult()中获得了不同的请求代码(102),但我们使用原始请求代码(FragmentA)调用 req code ::358 因此,我们将从NestedFragmentA -

获取这些日志
NestedFragmentA

现在来HomeActivity。我们假设您接受/拒绝 req code ::614 的许可,这样您就可以登录onRequestPermissionsResult() -

NestedFragmentA's onRequestPermissionsResult()

但我们知道不会为嵌套片段调用requestPermissions(),因此我们无法在requestPermissions()

中获取任何日志

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

所以我要说的是,对于那些没有从片段嵌套requestPermissions()的片段,只在那里实现STRSPLIT(string, regex, limit) 而不是在容器活动中。 对于嵌套片段,只有[\s,]+才能获得来自父片段的嵌套片段所需的权限。这似乎是唯一的解决方法。