Android 管理多个fragment(处理Activity被回收的情况)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 管理多个fragment(处理Activity被回收的情况)相关的知识,希望对你有一定的参考价值。

做了好久的项目,由于进度赶,也没怎么闲心来写博客。不过项目赶是赶,也不是一口就能吞掉的,要慢慢来。既然慢慢来,就抽出点时间来写点什么。在项目里遇到好几个棘手的问题。有几个是被我解决掉。其中一个就是多个fragment的管理问题。只能说我是android的新手,也没怎么系统学习android,所以有些东西,只能在项目里摸索,要用到哪个就学哪个,还好我还大概知道哪些该在哪用,哪些该是被学。

情景一:一个Activity中使用多个fragment,以tab的形式来点击切换fragment。一共用到了4个fragment,用一个全局的fragment数组保存了所有fragment的引用。在onCreate方法中完成实例化(默认显示第一个fragment)。
java
mContentFragments = new BaseFragment[4];

这样会造成一个问题,就是比如:当前你切换到了第2个fragment,应用切换到了后天,这时候这个Activity在后台被回收了,然后你不知道,你切回应用,Activity又重新调用了activity方法。然后你就憋屈了,因为应用又回到第一个fragment。
解决办法(如有高手有其他解决办法请告知在下!):
“`flow
st=>start: 应用进入后台
e=>end: 回到应用正常
op1=>operation: 调用onSaveInstanceState保持状态
cond=>condition: aty在后台被杀死?
op2=>operation: 调用onRestoreInstanceState恢复状态
st->op1->cond
cond(yes)->op2->e
cond(no)->e

  1. 由于我们一旦按了Home键,应用会转后台,aty会自动调用onSaveInstanceState保持状态,所以我们在onSaveInstanceState的方法里保存状态。aty在后台被杀死后,onSaveInstanceState中有保存状态,回到aty时会自动调用onRestoreInstanceState方法。
  2. ```java
  3. @Override
  4. protected void onSaveInstanceState(Bundle outState)
  5. {
  6. // mCurrentPosition表示当前切换的fragment的数组下标
  7. outState.putInt(POSITIONKEY, mCurrentPosition);
  8. //super.onSaveInstanceState(outState); 总是执行这句代码来调用父类去保存视图层的状态,会导致fragmen重影,不能正常恢复状态
  9. }
  10. @Override
  11. protected void onRestoreInstanceState(Bundle savedInstanceState)
  12. {
  13. // 获取保存的数组下标
  14. mCurrentPosition=savedInstanceState.getInt(POSITIONKEY);
  15. // 回复视图状态,恢复为fragmen的切换状态
  16. changeTabView(savedInstanceState.getInt(POSITIONKEY));
  17. super.onRestoreInstanceState(savedInstanceState);
  18. }
  19. ```
  20. **情景二:**aty被回收了,fragment没被回收(还在内存中,只是我们没有它们的引用)!
  21. 先晾一下切换fragment的代码先:
  22. ```java
  23. public void changeFragment(int resView, Fragment targetFragment)
  24. {
  25. if (targetFragment.equals(currentFragment))
  26. {
  27. return;
  28. }
  29. FragmentTransaction transaction = getFragmentManager()
  30. .beginTransaction();
  31. if (!targetFragment.isAdded())
  32. {// 如果这个fragment没被添加过
  33. transaction.add(resView, targetFragment, targetFragment.getClass()
  34. .getName());
  35. }
  36. if (targetFragment.isHidden())
  37. {// 如果这个fragment是被隐藏的
  38. transaction.show(targetFragment);
  39. }
  40. if (currentFragment != null && currentFragment.isVisible())
  41. {// 隐藏当前显示的fragment
  42. transaction.hide(currentFragment);
  43. }
  44. currentFragment = targetFragment;
  45. // 提交了才算完成
  46. transaction.commit();
  47. }
  48. ```
  49. 在这里的代码,我使用的是FragmentTransaction里的addshowhide方法,这样在fragment不多的情况下,可以保存fragment的状态,并提高了切换fragment的速度。但是这样的缺点在该情景下就有问题了。
  50. aty被回收,fragment还在内存中,在FragmentManager里,重新onCreate,重新实例化了新的一批fragment,然后一调用changeFragment方法。比如,FragmentManager里有一个FragmentA,我们又重新实例化一个FragmentA。由于两个FragmentA的对象在堆中不是同一个,故FragmentTransactionadd这个新的FragmentAFragmentManager中(会造成fragment重影),造成内存泄露。
  51. 所以,我们应该这么做(如有高手有其他解决办法请告知在下!):
  52. ```java
  53. @Override
  54. public void onCreate(Bundle savedInstanceState)
  55. {
  56. if (savedInstanceState != null)
  57. {
  58. // 防止fragment没被回收
  59. FragmentManager fm = getFragmentManager();
  60. mContentFragments = new BaseFragment[4];
  61. mContentFragments[0] = (BaseFragment) fm.findFragmentByTag(MainChatFragment2.class.getName());
  62. mContentFragments[1] = (BaseFragment) fm.findFragmentByTag(MainCircleFragment.class.getName());
  63. mContentFragments[2] = (BaseFragment) fm.findFragmentByTag(MainWallFragment.class.getName());
  64. mContentFragments[3] = (BaseFragment) fm.findFragmentByTag(MainFindFragment.class.getName());
  65. }
  66. super.onCreate(savedInstanceState);
  67. }




以上是关于Android 管理多个fragment(处理Activity被回收的情况)的主要内容,如果未能解决你的问题,请参考以下文章

Android Gems — Fragment本质之生命周期管理

Android Gems — Fragment本质之生命周期管理

Android--Fragment基本介绍

android fragment和activity的区别

Android Jetpack导航组件——Navigation的使用

Android安卓viewpager和Fragment的结合,多个Fragment视图之间切换等运用