Fragment请求权限,回调到onRequestPermissionsResult后requestCode改变了

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l460133921/article/details/83115358

1. 复现场景

我自定义 了一个继而自AppCompatActivity的Activity类,在该类中加载了一个自定义的AppTakephotoFragment, 关键代码如下:

public class FullScreenActivity extends AppCompatActivity {
    ......
 
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
    if(mTakephotoFragment != null){
        mTakephotoFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

AppTakephotoFragment中使用takephoto库拍照,继承自takephoto的TakePhotoFragment,主要代码如下:

public class AppTakephotoFragment extends TakePhotoFragment {
    ......
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        LinearLayout view = new LinearLayout(getActivity());
        takePhoto = getTakePhoto();
        takePhoto.onPickFromGallery();
        return view;
    }
    
    @Override
    public void takeCancel() {
        super.takeCancel();
        seReturnResult(null);
        close();
    }

    @Override
    public void takeFail(TResult result, String msg) {
        super.takeFail(result, msg);
        seReturnResult(null);
        close();
    }

    @Override
    public void takeSuccess(TResult result) {
        super.takeSuccess(result);
        if(result != null && result.getImage()!= null) {
            seReturnResult(result.getImage().getOriginalPath());
        }
        close();
    }

    private void close() {
        getActivity().finish();
    }

    private void seReturnResult(String dataString) {
        if(dataString != null) {
            Intent data = new Intent();
            data.setData(Uri.parse(dataString));
            getActivity().setResult(Activity.RESULT_OK, data);
        } else {
            getActivity().setResult(Activity.RESULT_CANCELED);
        }
    }
}

在onCreateView中调用onPickFromGallery时需要申请权限,当我选择拒绝授权时,发现并没有调用takeFail。

2. 问题原因

通过单步调试onPickFromGallery调用流程,发现在调用requestPermissions时传递的requestCode为2000,而在回调到TakePhotoFragment的onRequestPermissionsResult时传回来的requestCode为67536,由于非之前传递的2000,因此导致无法调用到takeFail。

3. 修改方法

按如下方法修改,代码如下:

public class FullScreenActivity extends AppCompatActivity {
    ......
 
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
    super.onRequestPermissionsResult(requestCode,permissions,grantResults); //添加该行代码即可修改
    if(mTakephotoFragment != null){
        mTakephotoFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

4. 根因分析

Fragment中requestPermisssions的调用流程如下:
在这里插入图片描述
具体的调用流程请读者自行分析,这里只介绍上图中标的两个关键函数requestPermissionsFromFragment和onRequestPermissionsResult。

4.1 requestPermissionsFromFragment

代码如下:

void requestPermissionsFromFragment(Fragment fragment, String[] permissions, int requestCode) {
        if (requestCode == -1) {
            ActivityCompat.requestPermissions(this, permissions, requestCode);
        } else {
            checkForValidRequestCode(requestCode); //验证requestCode,超过65535(0xFFFF)会报异常

            try {
                this.mRequestedPermissionsFromFragment = true;
                int requestIndex = this.allocateRequestIndex(fragment);//根据fragment请求权限的顺序分配索引
                ActivityCompat.requestPermissions(this, permissions, (requestIndex + 1 << 16) + (requestCode & '\uffff')); //requestCode改变了
            } finally {
                this.mRequestedPermissionsFromFragment = false;
            }

        }
    }

从代码中可以看到在调用ActivityCompat.requestPermissions时将requestCode修改成了(requestIndex + 1 << 16) + (requestCode & ‘\uffff’),这也是在调试过程中requestCode变为67536的原因。

4.2 onRequestPermissionsResult

先看下FragmentActivity中的onRequestPermissionsResult源代码,如下:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        mFragments.noteStateNotSaved();
        //去掉高于16位的(index)
        int index = (requestCode >> 16) & 0xffff; 
        if (index != 0) {
            index--; //index=0

            String who = mPendingFragmentActivityResults.get(index);
            mPendingFragmentActivityResults.remove(index);
            if (who == null) {
                Log.w(TAG, "Activity result delivered for unknown Fragment.");
                return;
            }
            //通过who拿到相应的Fragment
            Fragment frag = mFragments.findFragmentByWho(who); 
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for who: " + who);
            } else {
                //通过requestCode & 0xffff去掉高于16位的(index),恢复原来的requestCode
                frag.onRequestPermissionsResult(requestCode & 0xffff, permissions, grantResults); 
            }
        }
    }

由于FullScreenActivity 继承自AppCompatActivity,而AppCompatActivity又继承自FragmentActivity,因此在FullScreenActivity的onRequestPermissionsResult加入super.onRequestPermissionsResult,显式调用父类的super.onRequestPermissionsResult可以解决该问题。

猜你喜欢

转载自blog.csdn.net/l460133921/article/details/83115358