• 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仍然能通过,不要疑惑,你懂得!

  • 相关阅读:
    云存储研发工程师(40-50万)
    数据分析师(50-70万)
    云计算-资深java研发
    云计算 -- 资深python开发
    公众号”IT高薪猎头“
    51内核mcu实现printf的一种方法
    一种基于蓝牙BLE无线控制的灯光系统的解决方案
    Ecx后台增加新菜单+新数据表+新bundle完整过程
    Ecx 生成swagger文档
    ecshopx-manage管理后台本地编译设置本地API
  • 原文地址:https://www.cnblogs.com/aimqqroad-13/p/7478872.html
Copyright © 2020-2023  润新知