做了好久的项目,由于进度赶,也没怎么闲心来写博客。不过项目赶是赶,也不是一口就能吞掉的,要慢慢来。既然慢慢来,就抽出点时间来写点什么。在项目里遇到好几个棘手的问题。有几个是被我解决掉。其中一个就是多个fragment的管理问题。只能说我是android的新手,也没怎么系统学习android,所以有些东西,只能在项目里摸索,要用到哪个就学哪个,还好我还大概知道哪些该在哪用,哪些该是被学。
**情景一:**
一个Activity中使用多个fragment,以tab的形式来点击切换fragment。一共用到了4个fragment,用一个全局的fragment数组保存了所有fragment的引用。在onCreate方法中完成实例化(默认显示第一个fragment)。
1
| mContentFragments = new BaseFragment[4];
|
这样会造成一个问题,就是比如:当前你切换到了第2个fragment,应用切换到了后天,这时候这个Activity在后台被回收了,然后你不知道,你切回应用,Activity又重新调用了activity方法。然后你就憋屈了,因为应用又回到第一个fragment。
解决办法(如有高手有其他解决办法请告知在下!):
1
|
st=>start: 应用进入后台
e=>end: 回到应用正常
op1=>operation: 调用onSaveInstanceState保持状态
cond=>condition: aty在后台被杀死?
op2=>operation: 调用onRestoreInstanceState恢复状态
st->op1->cond
cond(yes)->op2->e
cond(no)->e
|
由于我们一旦按了Home键,应用会转后台,aty会自动调用onSaveInstanceState保持状态,所以我们在onSaveInstanceState的方法里保存状态。aty在后台被杀死后,onSaveInstanceState中有保存状态,回到aty时会自动调用onRestoreInstanceState方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Override protected void onSaveInstanceState(Bundle outState) {
outState.putInt(POSITIONKEY, mCurrentPosition);
}
@Override protected void onRestoreInstanceState(Bundle savedInstanceState) {
mCurrentPosition=savedInstanceState.getInt(POSITIONKEY);
changeTabView(savedInstanceState.getInt(POSITIONKEY)); super.onRestoreInstanceState(savedInstanceState); }
|
**情景二:**
aty被回收了,fragment没被回收(还在内存中,只是我们没有它们的引用)!
先晾一下切换fragment的代码先:
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
| public void changeFragment(int resView, Fragment targetFragment) { if (targetFragment.equals(currentFragment)) { return; } FragmentTransaction transaction = getFragmentManager() .beginTransaction(); if (!targetFragment.isAdded()) { transaction.add(resView, targetFragment, targetFragment.getClass() .getName()); } if (targetFragment.isHidden()) { transaction.show(targetFragment); } if (currentFragment != null && currentFragment.isVisible()) { transaction.hide(currentFragment); } currentFragment = targetFragment; transaction.commit(); }
|
在这里的代码,我使用的是FragmentTransaction里的add、show、hide方法,这样在fragment不多的情况下,可以保存fragment的状态,并提高了切换fragment的速度。但是这样的缺点在该情景下就有问题了。
aty被回收,fragment还在内存中,在FragmentManager里,重新onCreate,重新实例化了新的一批fragment,然后一调用changeFragment方法。比如,FragmentManager里有一个FragmentA,我们又重新实例化一个FragmentA。由于两个FragmentA的对象在堆中不是同一个,故FragmentTransaction会add这个新的FragmentA到FragmentManager中(会造成fragment重影),造成内存泄露。
所以,我们应该这么做(如有高手有其他解决办法请告知在下!):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { FragmentManager fm = getFragmentManager();
mContentFragments = new BaseFragment[4]; mContentFragments[0] = (BaseFragment) fm.findFragmentByTag(MainChatFragment2.class.getName()); mContentFragments[1] = (BaseFragment) fm.findFragmentByTag(MainCircleFragment.class.getName()); mContentFragments[2] = (BaseFragment) fm.findFragmentByTag(MainWallFragment.class.getName()); mContentFragments[3] = (BaseFragment) fm.findFragmentByTag(MainFindFragment.class.getName());
} super.onCreate(savedInstanceState); }
|