Android笔记之Fragment的startActivityForResult(与requestPermissions)

本文深入解析在Android开发中,Fragment如何正确使用startActivityForResult和requestPermissions,揭示requestCode转换背后的逻辑,确保与Activity请求区分,实现稳定回调。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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的请求

首先还是看源码:

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

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开发的初学者,如果我有错误的地方或者不足的话欢迎大家指正。希望与大家一同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值