Android笔记之Fragment的startActivityForResult(与requestPermissions)

1、fragment使用...的注意事项

首先是你们熟悉的,在fragment中使用startActivityForResult和requestPermissions的时候,要注意:bash

  • 使用fragment本身的方法,即Fragment.startActivityForResult和...,而不是fragment.getActivity(=FragmentActivity)的方法
  • 在Activity中的对应方法(onActivityResult和onRequestPermissionsResult)中不要去掉super.

原本我只是知其然但不知其因此然,可是一次debug让我了解了其中缘由。函数

2、 debug什么

这样的,我在fragment中发出startActivityForResult请求,在fragment所在的Activity中的onActivityResult打了个断点看一下,这一看就发现了有个问题:fragment中启动的requestCode是0,然而到了activity中的onResult的requestCode变成了65536。this

若是是别的数字的话可能会忽略掉,反正最后是能正常调用fragment的回调的,可是65536?2^16??0xffff+1?这个数字但是很特殊。在看了源码以后终于有了具体的解释,因此来看看发出请求到onResult的过程吧。spa

声明: 如下源码为API 27.1.1debug

3、(support)Fragment的请求

能够看到Fragment的startActivityForResult调用一个mHost的方法,这个mHost最后就是调用了FragmentActivity的startActivityFromFragment,那FragmentActivity作了什么呢?
code

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的了。cdn

Fragment的startActivityForResult总结

  • 传入的requestCode要不大于0xffff
  • 实际请求的requestCode作了转换,变成大于0xffff的数了,可是低8位仍然是原来的requestCode,高8位是requestIndex+1

4、 FragmentActivity的请求

首先仍是看源码:blog

嗯..那个check的函数就是上边那个,因此结果很清楚了。

FragmentActivity的startActivityForResult总结

  • 没干啥,就要求requestCode不大于0xffff,实际请求的requestCode没变

FragmentActivity的onActivityResult

首先咱们要明白,Fragment的请求也是先有FragmentActivity来处理的。而后通过上边的分析,咱们大概能够猜想,经过转换requestCode,Fragment和FragmentActivity的请求就被分开了,那onResult的时候也是分开处理的。来看code:开发

分开来看:get

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。

5、one more thing

以上是分析了startActivityForResult的流程,requestPermissions是相似的能够本身去看一遍。源码真的是好东西,Google的工程师也真的厉害,这个逻辑不难可是让我这种新手是很差想出来的。

//做为Android开发的初学者,若是我有错误的地方或者不足的话欢迎你们指正。但愿与你们一同进步。

相关文章
相关标签/搜索