Fragment之onActivityResult

我们都知道Activity下执行startActivityForResult 然后在onActivityResult函数中处理带回的结果,那么fragment中执行startActivityForResult而后其onActivityResult是否能够正确的被调用呢?
下图是实际调用的时序图:
Fragment->Fragment:startActivityForResult
Fragment->HostCallbacks:onStartActivityFromFragment
HostCallbacks->FragmentActivity:startActivityFromFragment
FragmentActivity->Fragment:onActivityResult

fragment执行startActivityForResult最终执行的是FragmentActivity的startActivityFromFragment函数,其中,新requestCode是根据fragment的index(高16位) + 原requestCode(低16位) 被重新计算的。

public void startActivityFromFragment(Fragment fragment, Intent intent,int requestCode) {if (requestCode == -1) {super.startActivityForResult(intent, -1);return;}if ((requestCode&0xffff0000) != 0) {throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");}super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));}

实际接受Result的还是Activity,Activity先会看看requestCode是不是由其fragment发出的(判断高16位是否有内容),如果是,则根据requestCode中解析得到index找到对应的fragment,并还原原requestCode(取低16位) ,最后调用fragmento的nActivityResult。
注:mActive是存放Fragment实例的队列,而mIndex则是某fragment在mActive中的序号

protected void onActivityResult(int requestCode, int resultCode, Intent data) {mFragments.noteStateNotSaved();int index = requestCode>>16;if (index != 0) {index--;final int activeFragmentsCount = mFragments.getActiveFragmentsCount();if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {Log.w(TAG, "Activity result fragment index out of range: 0x"+ Integer.toHexString(requestCode));return;}final List<Fragment> activeFragments =mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));Fragment frag = activeFragments.get(index);if (frag == null) {Log.w(TAG, "Activity result no fragment exists for index: 0x"+ Integer.toHexString(requestCode));} else {frag.onActivityResult(requestCode&0xffff, resultCode, data);}return;}super.onActivityResult(requestCode, resultCode, data);
}

然后再来到Fragment.java下。

public void onActivityResult(int requestCode, int resultCode, Intent data) {
}

发现这是个空函数,这意味着,
* Activity下的Fragment的onActivityResult是可以接收到Result.
* Fragment下的Fragment默认无法收到onActivityResult的结果的。要做到也可以,但自己需要实现规则。

Fragment下的Fragment 是无法收到Result,如何应对?

但是Fragment的嵌套使用并不少见,举例来说:Fragment A下使用到FragmentDialog B 及 FragmentDialog C 或更多,在B,C 使用场合中都会启动电话本,并且通过onActivityResult返回选择结果,那么在Result通过onActivityResult流入到A,那么A根据什么来判断 最后的结果是流向 B 还是C .

[*]–>FragmentActivity
FragmentActivity–>Fragment_A
Fragment_A–>Fragment_B
Fragment_A–>Fragment_C
Fragment_A:第一层级fragment
Fragment_B:startActivityResult()
Fragment_B:第二层级fragment
Fragment_C:startActivityResult()
Fragment_C:第二层级fragment

我的解决方案:

那还是借鉴系统的办法,系统将16~31位来存储区分FragmentActivity第一层级fragment的index,而0~15位存储实际的requestCode.而我为了区分第二层级的fragment,将第8~15位用来存储fragment的id号,将第0~7位用来存储实际的requestCode. 限制:需要定义的requestCode小于256

建立一个工具类

用来在第一层级fragment里进行requestCode的截获封装(对应startActivityForResult())及解析(对应onActivityResult())

public class FragmentForActivityResultHelper {public static final String CHILD_FRAGMENT_TAG = "child_fragment_tag";/*** 和childFragmentTag一一对应的id,不得大于0xff.*/private int childFragmentIndex = 0;/*** key是childFragmentIndex,值是childFragmentTag*/private HashMap<Integer, String> childFragmentTagMap = new HashMap<>();public void startActivityForResult(Intent intent, int requestCode, @NonNull Fragment fragment_) {Bundle b = intent.getExtras();String childFragmentTag;if (b != null) {childFragmentTag = (String) b.get(CHILD_FRAGMENT_TAG);if (childFragmentTag != null) {requestCode = getNewRequestCode(requestCode, childFragmentTag);}}fragment_.getActivity().startActivityForResult(intent, requestCode);}private synchronized int getNewRequestCode(int requestCode, String childFragmentTag) {if ((requestCode & 0xff00) != 0) {throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");}childFragmentIndex++;if (childFragmentIndex >= 0xff) {childFragmentIndex = 0;}int newRequestCode = ((childFragmentIndex << 8) + (requestCode & 0xff));childFragmentTagMap.put(newRequestCode, childFragmentTag);return newRequestCode;}/*** @return ture:说明该Result已经被处理了。   false:没有处理。*/public boolean onActivityResult(int requestCode, int resultCode, Intent data, Fragment fragment_) {if ((requestCode & 0xff00) != 0) {int key = requestCode & 0xffff;String tag = childFragmentTagMap.get(key);if (tag != null) {childFragmentTagMap.remove(key);Fragment fragment = fragment_.getChildFragmentManager().findFragmentByTag(tag);if (fragment != null) {fragment.onActivityResult(requestCode & 0xff, resultCode, data);return true;}}}return false;}
}

在第一层级Fragment中如何使用

“`
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(fragmentForActivityResultHelper.onActivityResult(requestCode,resultCode,data,this)) {
return;
}

/**在FragmentForActivityResultHelper对象没有处理ActivityResult的时候,这里进行其他requestCode的处理**/

}

@Override
public void startActivityForResult(Intent intent, int requestCode) {
fragmentForActivityResultHelper.startActivityForResult(intent,requestCode,this);
}

###在第二层级Fragment中如何使用

public void startActivityForResult(Intent intent, int requestCode) {
Fragment pf = getParentFragment();
intent.putExtra(FragmentForActivityResultHelper.CHILD_FRAGMENT_TAG, SHOPPING_ADDRESS_LIST);
if (pf != null) {
pf.startActivityForResult(intent, requestCode);
return;
}

Activity a = getActivity();
if (a != null) {a.startActivityForResult(intent, requestCode);
}

}
“`

适用场景

上面这样做的原因主要针对的场合是:
有两层fragment,并且有至少两个第二层级的fragment需要处理有相同requestCode的ActivityResult

周边影响:

场景1:有两层fragment,第二层级的fragment间没有处理相同requestCode的ActivityResult,

那么FragmentForActivityResultHelper其实根本用不上,只需要根据requestCode的值就能区分该将数据传给哪个fragment.
那如果只有其中一个使用了FragmentForActivityResultHelper而其他没有会有什么问题吗?不会。

场景2:只有一层fragment

这个问题就根本不存在。

场景3:

【Fragment】onActivityResult相关推荐

  1. 【Fragment】管理机制

    before 想想在fragment出现前我们如何实现类似fragment的功能呢?需求是要做一个相对独立的布局功能,可能在多个地方需要复用到,还有就是他需要能够被动态的切换,于是乎,写个layout ...

  2. 【fragment】Android Fragments 详细使用

    http://terryblog.blog.51cto.com/1764499/793310 Fragments 诞生初衷 自从Android 3.0中引入fragments 的概念,根据词海的翻译可 ...

  3. 【Fragment】FragmentManager和FragmentTransaction使用

    1.获得 FragmentManager FragmentManager fragmentManager = getSupportFragmentManager(); 2.使用 FragmentTra ...

  4. 【Android】底部导航栏【BottomNavigationView】+【ViewPage2】

    问题需求 实现底部导航栏切换 问题解决 最简单的实现方式就是使用系统自动生成的模板页面,但是有时候会有一些问题,特别是需要去除[ActionBar]的情况下,这种情况下使用系统的模板页面就不好用了,此 ...

  5. 【Android Fragment】解决Fragment多层嵌套时onActivityResult无法正确回调的问题

    前言: Fragment也可以使用startActivityForResult方法去打开一个Activity,然后在其onActivityResult方法中处理结果,可是当Fragment嵌套的时候, ...

  6. 【Android】保存Fragment切换状态

    [Android]保存Fragment切换状态 前言 一般频繁切换Fragment会导致频繁的释放和创建,如果Fragment比较臃肿体验就非常不好了,这里分享一个方法. 声明 欢迎转载,但请保留文章 ...

  7. 【转】解决Fragment already active方法

    [转]解决Fragment already active方法 参考文章: (1)[转]解决Fragment already active方法 (2)https://www.cnblogs.com/ex ...

  8. 2022年最新版Android安卓面试题+答案精选(每日20题,持续更新中)【一】

    前言 写在前面:首先是不一次性放出来的原因:资料来之不易,希望大家好好珍惜,每天花一段时间细细的消化这些题目,其次希望大家在阅读题目的时候最好跟着书或者代码一起阅读.一起敲,做到熟稔于心,信手拈来,这 ...

  9. 【推荐】MySQL Cluster报错及解决方法(不断更新中)

    排查问题技巧: MySQL Cluster 自带了一个错误代码的查看的小程序.通过这个小东西我们可以方便的定位问题的原因. 这个程序就是 perror 在MYSQL安装目录的bin下面. 如报错:ER ...

最新文章

  1. SpringMVC+MyBatis 事务管理一
  2. Python学习之路--函数
  3. Python中 ‘==‘ 与‘is‘ 以及它们背后的故事
  4. dism++封装系统使用教程_客栈管理系统“订单来了”客房订单盒子使用教程
  5. 边缘计算 ai_在边缘探索AI!
  6. 从零开始学习音视频编程技术(七) FFMPEG Qt视频播放器之SDL的使用
  7. C++socket编程(二):系统socket库介绍
  8. 【u107】数字游戏(bds)
  9. 【堆】这是要搞事情啊——取出
  10. RabbitMQ学习——整合Spring AMQP、SpringBoot以及Spring Cloud Stream
  11. javascript数据类型(摘录)
  12. [android] 代码注册广播接收者利用广播调用服务的方法
  13. 没解决:RuntimeWarning: tp_compare didn't return -1 or -2 for exception
  14. python应声虫程序_【Python】游戏-成语接龙
  15. SIFT算法系列之尺度空间
  16. html基础教程之HTML 标题
  17. matlab中eval函数作用6,Matlab中eval函数的使用方法
  18. C语言程序设计精髓 第14周——结构设计的艺术 练兵区——编程题
  19. 微信硬件平台wifi设备通信第一篇
  20. python的continue用法_Python学习笔记之Break和Continue用法分析

热门文章

  1. 河北高速盘点七大假牌假证违法案例:寒冬穿大裤衩开车
  2. 一种轻量级的C4C业务数据同步到S/4HANA的方式:Odata通知
  3. CDN的工作原理以及其中的一些技术-阿里
  4. Redis数据类型操作(一) —— String
  5. Windows下Nginx+Tomcat整合的安装与配置
  6. FZU 2159 WuYou
  7. 获取图片像素颜色,转换为CSS3 box-shadow显示
  8. Android Service的绑定 基础概念篇
  9. container_of分析
  10. 查看SQL Server Resource Database以及修改系统表