解决Fragment多层嵌套时onActivityResult无法正确回调的问题

举报
再见孙悟空_ 发表于 2022/01/13 22:35:47 2022/01/13
【摘要】 Fragment也可以使用startActivityForResult方法去打开一个Activity,然后在其onActivityResult方法中处理结果,可是当Fragment嵌套的时候,由于FragmentActivity的BUG导致只会回调最外那层Fragment的onActivityResult方法,于是乎当前Fragment...

Fragment也可以使用startActivityForResult方法去打开一个Activity,然后在其onActivityResult方法中处理结果,可是当Fragment嵌套的时候,由于FragmentActivity的BUG导致只会回调最外那层Fragment的onActivityResult方法,于是乎当前Fragment就收不到结果了。

我们先从Fragment的startActivityForResult开始分析


  
  1. public void startActivityForResult(Intent intent, int requestCode) {
  2. if(this.mActivity == null) {
  3. throw new IllegalStateException("Fragment " + this + " not attached to Activity");
  4. } else {
  5. this.mActivity.startActivityFromFragment(this, intent, requestCode);
  6. }
  7. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

很明显直接调用了FragmentActivity的startActivityFromFragment方法


  
  1. public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
  2. if(requestCode == -1) {
  3. super.startActivityForResult(intent, -1);
  4. } else if((requestCode & -65536) != 0) {
  5. throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
  6. } else {
  7. super.startActivityForResult(intent, (fragment.mIndex + 1 << 16) + (requestCode & '\uffff'));
  8. }
  9. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里将requestCode和Fragment的mIndex融合成了一个整型作为新的requestCode,那么新的requestCode的高16位表示Fragment的索引,低16为表示原本的requestCode,看来这里是用Fragment的mIndex作为查找依据的

接下来再看FragmentActivity的onActivityResult方法


  
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  2. this.mFragments.noteStateNotSaved();
  3. int index = requestCode >> 16;
  4. if(index != 0) {
  5. --index;
  6. if(this.mFragments.mActive != null && index >= 0 && index < this.mFragments.mActive.size()) {
  7. Fragment frag = (Fragment)this.mFragments.mActive.get(index);
  8. if(frag == null) {
  9. Log.w("FragmentActivity", "Activity result no fragment exists for index: 0x" + Integer.toHexString(requestCode));
  10. } else {
  11. frag.onActivityResult(requestCode & '\uffff', resultCode, data);
  12. }
  13. } else {
  14. Log.w("FragmentActivity", "Activity result fragment index out of range: 0x" + Integer.toHexString(requestCode));
  15. }
  16. } else {
  17. super.onActivityResult(requestCode, resultCode, data);
  18. }
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里取出requestCode的高16位,不等0就是子Fragment的mIndex,但是接下来却直接从Activity的Fragment列表中根据索引去找Fragment,如果你的Fragment是被子Fragment的childFragmentManager管理的话这样是绝对找不到的,于是乎答案很明了了。

解决问题: 
解决这个问题的办法有两个 
第一个是直接升级support-v4到23.2.0以上的版本,因为23.2.0以上就修复了这个BUG,具体怎么解决的就不再赘述了有兴趣的可自行研究,但由于种种原因没办法升级23.2.0的还大有人在 
第二种办法就是自己动手丰衣足食,在Fragment层重写相关方法解决问题

接下来着重介绍自己动手丰衣足食的办法,完整实现如下:


  
  1. public class ForResultNestedCompatFragment extends Fragment {
  2. private ForResultNestedCompatFragment forResultChildFragment;
  3. @Override
  4. public void startActivityForResult(Intent intent, int requestCode) {
  5. Fragment parentFragment = getParentFragment();
  6. if (parentFragment != null && parentFragment instanceof ForResultNestedCompatFragment) {
  7. ((ForResultNestedCompatFragment) parentFragment).startActivityForResultFromChildFragment(intent, requestCode, this);
  8. } else {
  9. forResultChildFragment = null;
  10. super.startActivityForResult(intent, requestCode);
  11. }
  12. }
  13. private void startActivityForResultFromChildFragment(Intent intent, int requestCode, ForResultNestedCompatFragment childFragment) {
  14. forResultChildFragment = childFragment;
  15. Fragment parentFragment = getParentFragment();
  16. if (parentFragment != null && parentFragment instanceof ForResultNestedCompatFragment) {
  17. ((ForResultNestedCompatFragment) parentFragment).startActivityForResultFromChildFragment(intent, requestCode, this);
  18. } else {
  19. super.startActivityForResult(intent, requestCode);
  20. }
  21. }
  22. @Override
  23. public final void onActivityResult(int requestCode, int resultCode, Intent data) {
  24. if (forResultChildFragment != null) {
  25. forResultChildFragment.onActivityResult(requestCode, resultCode, data);
  26. forResultChildFragment = null;
  27. } else {
  28. onActivityResultNestedCompat(requestCode, resultCode, data);
  29. }
  30. }
  31. public void onActivityResultNestedCompat(int requestCode, int resultCode, Intent data) {
  32. }
  33. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

具体思路一句话概括就是startActivityForResult的时候一层一层往上让父Fragment持有子Fragment的引用,回调onActivityResult的时候父Fragment再一层一层传给子Fragment

具体用法就是让所有的Fragment都继承ForResultNestedCompatFragment,然后用onActivityResultNestedCompat方法替换onActivityResult方法

文章来源: wukong.blog.csdn.net,作者:再见孙悟空_,版权归原作者所有,如需转载,请联系作者。

原文链接:wukong.blog.csdn.net/article/details/55096792

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。