一、 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 */ |
/** * 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 /**
|
通过以上代码的比较我们知道,会造成下面的错误,是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仍然能通过,不要疑惑,你懂得!