原因:
使用 Fragment 的狀態(tài)保存哆姻,當(dāng)系統(tǒng)內(nèi)存不足台谊,F(xiàn)ragment 的宿主 Activity 回收的時(shí)候麻蹋,
Fragment 的實(shí)例并沒(méi)有隨之被回收皂贩。Activity 被系統(tǒng)回收時(shí)菲驴,會(huì)主動(dòng)調(diào)用 onSaveInstance()
方法來(lái)保存視圖層(View Hierarchy)会傲,所以當(dāng) Activity 通過(guò)導(dǎo)航再次被重建時(shí)混卵,
之前被實(shí)例化過(guò)的 Fragment 依然會(huì)出現(xiàn)在 Activity 中,此時(shí)的 FragmentTransaction 中的
相當(dāng)于又再次 add 了 fragment 進(jìn)去的恶阴,hide()和show()方法對(duì)之前保存的fragment已經(jīng)
失效了诈胜。綜上這些因素導(dǎo)致了多個(gè)Fragment重疊在一起。
解決方法:
第一種
1.給每個(gè) Fragment 加一個(gè) Tag
2.在 onCreate(Bundle savedInstanceState) 中判斷 Bundle savedInstanceState 是否不為空
3.不為空則進(jìn)行 find Tag冯事,重新給幾個(gè) frament 賦值
這樣子仍是對(duì)之前保存的 fragment 操作焦匈,成功解決了重疊的問(wèn)題。
kotlin寫(xiě)法
class MainActivity : AppCompatActivity() {
private var mHomeFragment: HomeFragment? = null
private var mMessageFragment: MessageFragment? = null
private var mMineFragment: MineFragment? = null
private var mPreFragment: Fragment? = null
private lateinit var mTransaction: FragmentTransaction
override fun onCreate(savedInstanceState: Bundle?) {
mTransaction = supportFragmentManager.beginTransaction()
//savedInstanceState不為空, 狀態(tài)恢復(fù)時(shí), 重新查找一遍, 重新賦值
savedInstanceState?.let {
mHomeFragment = mHomeFragment ?: supportFragmentManager.findFragmentByTag("0") as HomeFragment
mMessageFragment = mMessageFragment ?: supportFragmentManager.findFragmentByTag("1") as MessageFragment
mMineFragment = mMineFragment ?: supportFragmentManager.findFragmentByTag("2") as MineFragment
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initData()
}
private fun initData() {
//選中監(jiān)聽(tīng)
mRgBottomMenu.setOnCheckedChangeListener { _, checkedId ->
val transaction = supportFragmentManager.beginTransaction()
mPreFragment?.let {
transaction.hide(it)
}
when (checkedId) {
R.id.mRbHome -> //home界面
mHomeFragment =
mHomeFragment?.apply { showFragment(transaction, this) }
?: addFragment(transaction, 0) as HomeFragment
R.id.mRbMessage ->//消息界面
mMessageFragment =
mMessageFragment?.apply { showFragment(transaction, this) }
?: addFragment(transaction, 1) as MessageFragment
R.id.mRbMine -> //我的界面
mMineFragment =
mMineFragment?.apply { showFragment(transaction, this) }
?: addFragment(transaction, 2) as MineFragment
}
transaction.commitAllowingStateLoss()
}
mRbHome.isChecked = true
}
//顯示已經(jīng)存在的fragment
private fun showFragment(transaction: FragmentTransaction, fragment: Fragment) {
transaction.show(fragment)
mPreFragment = fragment
Log.d("test:: ", "show: ${fragment::class.java.simpleName} - $fragment")
}
//添加第一次創(chuàng)建實(shí)例的fragment
private fun addFragment(transaction: FragmentTransaction, type: Int): Fragment {
val fragment = when (type) {
0 -> HomeFragment()
1 -> MessageFragment()
else -> MineFragment()
}
transaction.add(R.id.mFlRoot, fragment, "$type")
mPreFragment = fragment
Log.d("test:: ", "add: ${fragment::class.java.simpleName} - $fragment")
return fragment
}
}
java寫(xiě)法
public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {
private TextView mTvTitle;
private LinearLayout mLlActionbar;
private FrameLayout mFlRoot;
private RadioButton mRbHome;
private RadioButton mRbMessage;
private RadioButton mRbMine;
private RadioGroup mRgBottomMenu;
private HomeFragment mHomeFragment;
private MessageFragment mMessageFragment;
private MineFragment mMineFragment;
private Fragment mPreFragment;
private FragmentManager mFragmentManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragmentManager = getSupportFragmentManager();
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mHomeFragment = (HomeFragment) mFragmentManager.findFragmentByTag("HomeFragment");
mMessageFragment = (MessageFragment) mFragmentManager.findFragmentByTag("MessageFragment");
mMineFragment = (MineFragment) mFragmentManager.findFragmentByTag("MineFragment");
}
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}
//可要可不要
@Override
public void onAttachFragment(@NonNull Fragment fragment) {
// if (mHomeFragment == null && fragment instanceof HomeFragment) {
// mHomeFragment = (HomeFragment) fragment;
// } else if (mMessageFragment == null && fragment instanceof MessageFragment) {
// mMessageFragment = (MessageFragment) fragment;
// } else if (mMineFragment == null && fragment instanceof MineFragment) {
// mMineFragment = (MineFragment) fragment;
// }
}
private void initView() {
mTvTitle = findViewById(R.id.mTvTitle);
mLlActionbar = findViewById(R.id.mLlActionbar);
mFlRoot = findViewById(R.id.mFlRoot);
mRbHome = findViewById(R.id.mRbHome);
mRbMessage = findViewById(R.id.mRbMessage);
mRbMine = findViewById(R.id.mRbMine);
mRgBottomMenu = findViewById(R.id.mRgBottomMenu);
}
private void initData() {
}
private void initListener() {
mRgBottomMenu.setOnCheckedChangeListener(this);
// mRgBottomMenu.check(R.id.mRbHome);
mRbHome.setChecked(true);
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
if (mPreFragment != null) {
transaction.hide(mPreFragment);
}
switch (checkedId) {
case R.id.mRbHome:
if (mHomeFragment == null) {
mHomeFragment = new HomeFragment();
transaction.add(R.id.mFlRoot, mHomeFragment, "HomeFragment");
} else {
transaction.show(mHomeFragment);
}
mPreFragment = mHomeFragment;
break;
case R.id.mRbMessage:
if (mMessageFragment == null) {
mMessageFragment = new MessageFragment();
transaction.add(R.id.mFlRoot, mMessageFragment, "MessageFragment");
} else {
transaction.show(mMessageFragment);
}
mPreFragment = mMessageFragment;
break;
case R.id.mRbMine:
if (mMineFragment == null) {
mMineFragment = new MineFragment();
transaction.add(R.id.mFlRoot, mMineFragment, "MineFragment");
} else {
transaction.show(mMineFragment);
}
mPreFragment = mMineFragment;
break;
}
transaction.commitAllowingStateLoss();
}
}
第二種
Activity 中的 onSaveInstanceState() 里面有一句super.onSaveInstanceState(outState);昵仅,
Google 對(duì)于這句話(huà)的解釋是 “Always call the superclass so it can save the view hierarchy state”缓熟,
大概意思是“總是執(zhí)行這句代碼來(lái)調(diào)用父類(lèi)去保存視圖層的狀態(tài)”。通過(guò)注釋掉這句話(huà)摔笤,
這樣主 Activity 因?yàn)榉N種原因被回收的時(shí)候就不會(huì)保存之前的 fragment state够滑,
也可以成功解決重疊的問(wèn)題。
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
// super.onSaveInstanceState(outState);
}
fragment 回退棧有關(guān)問(wèn)題
通常使用fragmentManager.beginTransaction().addToBackStack(null);
但是也經(jīng)常會(huì)遇到說(shuō)“某個(gè)fragment”已經(jīng)被添加的錯(cuò)誤吕世,這往往是我們?cè)趯?duì)fragment進(jìn)行返回處理時(shí)出現(xiàn)問(wèn)題彰触。這樣的問(wèn)題最常出現(xiàn)在我們點(diǎn)擊界面進(jìn)行跳轉(zhuǎn)的時(shí)候。
一般情況命辖,當(dāng)我們點(diǎn)擊導(dǎo)航欄進(jìn)行界面切換之后况毅,之前back stack中保存的fragment也就不再需要保留了。用下面的語(yǔ)句可以將back stack清空尔艇,同時(shí)也可避免上述錯(cuò)誤的出現(xiàn)尔许。
FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);