Fragment嵌套后,二级fragment onactivityresult失效解决办法

在使用fragment时如果需要和新的activity进行数据交互,通常会想到使用startActivityForResult方法,但是使用过程中发现有时候OnActivityResult方法不会调用。

第一种情况:

fragment.java 中

<span style="font-family:SimSun;font-size:18px;">getActivity().startActivityForResult(intent,1001);</span>

这种情况下fragmentActivity下的onActivityResult方法被调用。fragment中的onActivityResult不会被调用。

第二种情况:

fragment.java 中

<span style="font-family:SimSun;font-size:18px;">startActivityForResult(intent,1001);</span>

这种情况下fragmentActivity下的onActivityResult方法被调用,同时注意的是如果fragmentActivity下的onActivityResult方法调用了super.onActivityResult方法,fragment中的onActivityResult也会被调用。

一般情况下使用第二种情况,且不重载fragmentActivity下的onActivityResult方法,除非fragment和activity有互动。出现失效的原因大多是重载fragmentActivity下的onActivityResult方法但是没有调用super.onActivityResult方法

startActivityForResult

requestCode的可用区间:

1.Activity: [Integer.MIN_VALUE, Integer.MAX_VALUE]
(1)当requestCode取值在[Integer.MIN_VALUE, -1]区间中,效果和startActivity()一样,不会收到onActivityResult()回调
(2)内置的Fragment可用requestCode的区间和Activity相同
2.support库: Fragment,以及FragmentActivity:[-1, 65535]
(1)requestCode == -1,效果和startActivity()一样,不会收到onActivityResult()回调
(2)requestCode 在 [Integer.MIN_VALUE, -2]或者[65536, Integer.MAX_VALUE]之间,会抛出异常(requestCode只能使用低16比特)
建议: requestCode的取值统一限制在[-1, 65535]之间

嵌套Fragment

首先要说的是尽量不要使用嵌套Fragment.
当在嵌套Fragment中使用startActivityForResult()时,会遇到的问题:

所有的Fragment都收不到onActivityResult()
某个level 1 的Fragment收到了onActivityResult()
总之那个发起startActivityForResult()的嵌套Fragment是一定不会收到onActivityResult()回调的.

原因如下:(可参考上面说的requestCode)
FragmentActivity.startActivityFromFragment()会改动requestCode,用高16比特存储Fragment在FragmentManager中的index,而低16比特作为Fragment可用的requestCode.在FragmentActivity.onActivityResult()中,根据高16比特,从FragmentManager中找到对应的Fragment,然后将低16比特的值作为requestCode,调用Fragment.onActivityResult().

那么requestCode中只能存储一个index,即root FragmentManager中的Fragment index.因此就会出现上面所列出的情形:

  • 当嵌套Fragment在childFragmentManager中的index,大于rootFragmentManager中的所有index时, rootFragmentManager将找不到与此index对应的Fragment,所以没有Fragment能收到onActivityResult()
  • 当嵌套Fragment在childFragmentManager中的index,小于等于rootFragmentManager中的所有index时,那么隶属于rootFragmentManager的一个Fragment将会收到onActivityResult()
  • 总之即使能有Fragment能收到onActivityResult(),那也是顶层的某个Fragment,而不是发起请求的嵌套Fragment

解决方案:

  • 不使用嵌套Fragment :)
  • 依然利用requestCode,将其低16位拆分,其中的高8位用来存储childFragmentManager中的index,低8位留给ChildFragment使用.(如果嵌套层级不深,那么此方案还是不错的,如果层级较深,那么留给Fragment的requestCode的可用值区间将非常局限)
  • Android 4.2(Api 17)以后,可以使用内置的Fragment,以及ChildFragmentManager,内置Fragment不再需要借助requestCode的高16比特来记录它的index.而是由Framework收到Fragment.startActivityForResult()时,记录该Fragment的标识(android:fragment:${parentIndex}:${myIndex}),派发result时,就根据这个标识找到那个Fragment.因此就不会出现ChildFragment收不到onActivityResult()回调的问题了.可以参考Activity.dispatchActivityResult()
下面还有一种方法就是自己主动调用对应的fragment的onActivityResult方法。

具体实现如下:

在Activity中:

@Override
protected void onActivityResult(int requestCode, int ResultCode, Intent
        data) {
    super.onActivityResult(requestCode, ResultCode, data);
    // FragmentActivity.startActivityFromFragment()会改动requestCode,
    // 用高16比特存储Fragment在FragmentManager中的index,
    // 而低16比特作为Fragment可用的requestCode.
    // 在FragmentActivity.onActivityResult()中,根据高16比特,
    // 从FragmentManager中找到对应的Fragment,然后将低16比特的值作为requestCode,
    // 调用Fragment.onActivityResult().这里自己主动调用,将requestCode取低16bit数据
    if (mFragment != null) {
        mFragment.onActivityResult(requestCode & 0xffff, ResultCode, data);
    }
}

在一级fragment中

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (mChildFragment!= null) {
        mChildFragment.onActivityResult(requestCode,resultCode,data);
    }
}
这样就会调用二级fragment的onActivityResult了。
 
至于更深的嵌套理论上用这个方法应该也能实现,但是如果嵌套了这么多层是否应该考虑下代码设计的不够合理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值