Android requestCode的限制

一、 why ?

  由于才疏学浅,在开发中requestCode的让我很困惑。困惑是因为什么呢,是因为弄混了。要想弄明白,不困惑,来想一想用到requestCode的地方:

  ① startActivityForResult开启另一个Activity的时候:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
   }

  ② 请求权限的时候:

public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (mHasCurrentPermissionsRequest) {
            Log.w(TAG, "Can reqeust only one set of permissions at a time");
            // Dispatch the callback with empty arrays which means a cancellation.
            onRequestPermissionsResult(requestCode, new String[0], new int[0]);
            return;
        }
        Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
        mHasCurrentPermissionsRequest = true;
    }

(1)首先来看startActivityForResult()的requestCode:

  通过查看源码发现:在Activity中startActivityForResult() 和Activity的子类FragmentActivity中的startActivityForResult()是不一样的,代码展示区别:

/**
     * Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
     * with no options.
     *
     * @param intent The intent to start.
     * @param requestCode If >= 0, this code will be returned in
     *                    onActivityResult() when the activity exits.
     *
     * @throws android.content.ActivityNotFoundException
     *
     * @see #startActivity
     */
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); }

 

/**
     * Modifies the standard behavior to allow results to be delivered to fragments.
     * This imposes a restriction that requestCode be <= 0xffff.
     */
    @Override
    public void startActivityForResult(Intent intent, int requestCode) {
        // If this was started from a Fragment we've already checked 
     // the upper 16 bits were not in
// use, and then repurposed them for the Fragment's index. if (!mStartedActivityFromFragment) { if (requestCode != -1) { checkForValidRequestCode(requestCode); } } super.startActivityForResult(intent, requestCode); }


/**
* Checks whether the given request code is a valid code by masking it with 0xffff0000. Throws
* an {@link IllegalArgumentException} if the code is not valid.
*/
static void checkForValidRequestCode(int requestCode) {
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
}
 

 

通过以上代码的比较我们知道,会造成下面的错误,是FragmentActivity添加的限制,而Activity中没有该限制,这里解决了一点点疑惑:

java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode

所以这里总结一下:在startActivityForResult()中的resquestCode的限制是  0 <= requestCode <= 216,小于零会造成什么问题,你可以试试,我没有尝试。

(2)再来看ActivityCompat请求权限中的requestCode:

public static void requestPermissions(final @NonNull Activity activity,
            final @NonNull String[] permissions, final int requestCode) {
        if (Build.VERSION.SDK_INT >= 23) {
            ActivityCompatApi23.requestPermissions(activity, permissions, requestCode);
        } else if (activity instanceof OnRequestPermissionsResultCallback) {
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    final int[] grantResults = new int[permissions.length];

                    PackageManager packageManager = activity.getPackageManager();
                    String packageName = activity.getPackageName();

                    final int permissionCount = permissions.length;
                    for (int i = 0; i < permissionCount; i++) {
                        grantResults[i] = packageManager.checkPermission(
                                permissions[i], packageName);
                    }

                    ((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult(
                            requestCode, permissions, grantResults);
                }
            });
        }
    }

由源码可以知道:当sdk >=23的时候,会走 ActivityCompatApi23.requestPermissions(activity, permissions, requestCode),来看看它干了什么:

public static void requestPermissions(Activity activity, String[] permissions,
            int requestCode) {
        if (activity instanceof RequestPermissionsRequestCodeValidator) {
            ((RequestPermissionsRequestCodeValidator) activity)
                    .validateRequestPermissionsRequestCode(requestCode);
        }
        activity.requestPermissions(permissions, requestCode);
    }

如果Activity实现了接口RequestPermissionsRequestCodeValidator 就会对requestCode进行判断,天啊,终于说到它了。validateRequestPermissionsRequestCode 见名之意,它对requestCode作了限制,看看FragmentActivity实现的该接口是怎么限制的:checkForValidRequestCode() 这个方法是不是很熟悉:上面就有看看吧,看来限制是一样的: 请求权限              requestCode <= 216

 @Override
    public final void validateRequestPermissionsRequestCode(int requestCode) {
        // We use 16 bits of the request code to encode the fragment id when
        // requesting permissions from a fragment. Hence, requestPermissions()
        // should validate the code against that but we cannot override it as
        // we can not then call super and also the ActivityCompat would call
        // back to this override. To handle this we use dependency inversion
        // where we are the validator of request codes when requesting
        // permissions in ActivityCompat.
        if (!mRequestedPermissionsFromFragment
                && requestCode != -1) {
            checkForValidRequestCode(requestCode);
        }
    }

你会不会以为这个限制只有在sdk >=23以上才有,那就错了。我们来看看小于23时的分支会直接走到onRequestPermissionsResult(),来看看它:哇,同样的限制。

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        int index = (requestCode >> 16) & 0xffff;
        if (index != 0) {
            index--;

            String who = mPendingFragmentActivityResults.get(index);
            mPendingFragmentActivityResults.remove(index);
            if (who == null) {
                Log.w(TAG, "Activity result delivered for unknown Fragment.");
                return;
            }
            Fragment frag = mFragments.findFragmentByWho(who);
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for who: " + who);
            } else {
                frag.onRequestPermissionsResult(requestCode & 0xffff, permissions, grantResults);
            }
        }
    }

二、总结:

FragmentActivity是对Activtiy的一层包装,requestCode的限制是在它里面添加的,而Activity本身对requestCode是没有限制的。所以如果发现有的requestCode大于216仍然能通过,不要疑惑,你懂得!

转载于:https://www.cnblogs.com/aimqqroad-13/p/7478872.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值