零
一、fragment使用...的注意事项
首先是大家熟悉的,在fragment中使用startActivityForResult和requestPermissions的时候,要注意:
- 使用fragment自己的方法,即Fragment.startActivityForResult和...,而不是fragment.getActivity(=FragmentActivity)的方法
- 在Activity中的对应方法(onActivityResult和onRequestPermissionsResult)中不要去掉super.
本来我只是知其然但不知其所以然,但是一次debug让我了解了其中原因。
二、 debug什么
这样的,我在fragment中发出startActivityForResult请求,在fragment所在的Activity中的onActivityResult打了个断点看一下,这一看就发现了有个问题:fragment中启动的requestCode是0,然而到了activity中的onResult的requestCode变成了65536。
如果是别的数字的话可能会忽略掉,反正最后是能正常调用fragment的回调的,但是65536?2^16??0xffff+1?这个数字可是很特殊。在看了源码之后终于有了具体的解释,所以来看看发出请求到onResult的过程吧。
声明: 以下源码为API 27.1.1
三、(support)Fragment的请求
可以看到Fragment的startActivityForResult调用一个mHost的方法,这个mHost最后就是调用了FragmentActivity的startActivityFromFragment,那FragmentActivity做了什么呢?
requestCode = -1
这是没有result的startActivity用的,暂且不表,下边是重要的部分了,check的函数我也放到一起了:
static void checkForValidRequestCode(int requestCode) {
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
}
...
checkForValidRequestCode(requestCode);
int requestIndex = allocateRequestIndex(fragment);
ActivityCompat.startActivityForResult(
this, intent,
((requestIndex + 1) << 16) + (requestCode & 0xffff), options);
复制代码
首先是检查requestCode,高16位不能有1,即requestcode不能大于0xffff,requestIndex可以理解成fragment的一个标识编号,fragmentActivity来管理的。
重点在这里: 在实际用ActivityCompact启动请求的时候,传入的requestCode并不是我们设置的requestCode了,做了一个转换,((requestIndex + 1) << 16) + (requestCode & 0xffff)
这个转换的意思就是requestIndex+1放在高16位,requestCode的低16位放在新的低16位,这样组成了新的requestCode,写成数学表达式就是:requestCode = (requestIndex+1)*0xffff+requeseCode
这样新的requestCode就是大于0xffff的了。
Fragment的startActivityForResult总结
- 传入的requestCode要不大于0xffff
- 实际请求的requestCode做了转换,变成大于0xffff的数了,但是低8位仍然是原来的requestCode,高8位是requestIndex+1
四、 FragmentActivity的请求
首先还是看源码:
FragmentActivity的startActivityForResult总结
- 没干啥,就要求requestCode不大于0xffff,实际请求的requestCode没变
FragmentActivity的onActivityResult
首先我们要明白,Fragment的请求也是先有FragmentActivity来处理的。然后经过上边的分析,我们大概可以猜测,通过转换requestCode,Fragment和FragmentActivity的请求就被分开了,那onResult的时候也是分开处理的。来看code:
分开来看:
int requestIndex = requestCode>>16;
if (requestIndex != 0) {
requestIndex--;
...
}
复制代码
首先是除以(右移)16,这样剩下的就是高16位,如果不为0的话,就说明requestCode是大于0xffff的,就是我们Fragment发出的请求,不为0的高16位就是requestIndex。下边就是根据requestIndex找到对应的Fragment了
targetFragment.onActivityResult(
requestCode & 0xffff, resultCode, data);
复制代码
这是真正调用找到的Fragment的onResult的地方,由于请求的时候requestCode经过了转换,所以这里要转换回来,取出低16位就是原来的requestCode。
五、one more thing
以上是分析了startActivityForResult的流程,requestPermissions是类似的可以自己去看一遍。源码真的是好东西,Google的工程师也真的厉害,这个逻辑不难但是让我这种新手是不好想出来的。
//作为Android开发的初学者,如果我有错误的地方或者不足的话欢迎大家指正。希望与大家一同进步。