前言:在APP首頁很多時(shí)候都會(huì)用到多個(gè)fragment之間的切換唐责,如果用replace來完成切換固然會(huì)避免很多不必要的問題愧薛,但是不能保存頁面狀態(tài),對(duì)用戶體驗(yàn)明顯不太友好俏橘,頁面重新加載也會(huì)造成卡頓,作為程序員應(yīng)該盡量避免這類問題井联,因此本文將會(huì)詳細(xì)記錄這種問題的處理方案
最近測(cè)試提交了個(gè)bug卜壕,不過是很容易復(fù)現(xiàn),以下是測(cè)試原話
手機(jī)放一段時(shí)間過后滑動(dòng)首頁頁面會(huì)出現(xiàn)重疊
聽到重疊這兩個(gè)字我心里就有數(shù)了,一般都是activity的意外銷毀,導(dǎo)致activity保存了已添加過的fragment實(shí)例烙常,在activity重建的時(shí)候會(huì)默認(rèn)添加add到當(dāng)前activity上轴捎,而我們新建的fragment根據(jù)邏輯也會(huì)add到activity之上,這就造成了fragment的重疊军掂。
以下我首頁切換fragment的代碼轮蜕,在add的時(shí)候添加一個(gè)當(dāng)前fragment的全類名作為tag,為什么用這個(gè)當(dāng)tag蝗锥,后文中會(huì)提到跃洛,這里先賣個(gè)關(guān)子
private fun switchFragment(fragment: Fragment) {
val tag = fragment::class.java.name
val findFragmentByTag = supportFragmentManager.findFragmentByTag(currentTag)
if (findFragmentByTag != null && findFragmentByTag.isAdded && !findFragmentByTag.isHidden) {
supportFragmentManager.beginTransaction().hide(findFragmentByTag).commit()
}
if (fragment.isAdded) {
supportFragmentManager.beginTransaction().show(fragment).commit()
} else {
supportFragmentManager.beginTransaction()
.add(R.id.mainContainer, fragment, tag)
.commit()
}
currentTag = tag
}
當(dāng)activity意外銷毀會(huì)調(diào)用onSaveInstanceState(outState: Bundle?),這里一定要看清楚终议,這里是一個(gè)參數(shù)汇竭,別用成了兩個(gè)參數(shù)的,為什么要強(qiáng)調(diào)這里穴张,當(dāng)然是我之前出過錯(cuò)跋噶恰!皂甘!tags是fragment對(duì)應(yīng)的tag集合玻驻,這里保存起來,恢復(fù)的時(shí)候就不用重新添加了
private val _saveKey = "saveKey"
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState!!.putSerializable(_saveKey,tags)
}
在activity重建的時(shí)候還是走onCreate(savedInstanceState: Bundle?)偿枕,判斷里面的savedInstanceState不為null就表示是意外銷毀的情況璧瞬,下面的反射可以可以說是本篇的亮點(diǎn)了,這也是前文tag傳全類名的原因所在,還是有點(diǎn)精髓哈渐夸,有點(diǎn)小開心嗤锉,哈哈哈哈
private fun initViews(savedInstanceState: Bundle?) {
if (savedInstanceState != null) {
val serializable = savedInstanceState.getSerializable(_saveKey) as ArrayList<String>
tags.addAll(serializable)
for (tag in tags) {
var findFragmentByTag = supportFragmentManager.findFragmentByTag(tag)
if (findFragmentByTag == null) {
//這里通過tag反射獲取fragment的類,newInstance()獲取Fragment實(shí)例
val loadClass = savedInstanceState.classLoader.loadClass(tag)
findFragmentByTag = loadClass.newInstance() as Fragment
}
fragments.add(findFragmentByTag)
}
} else {
tags.clear()
tags.add(JournalFragment::class.java.name)
tags.add(WaitingFragment::class.java.name)
tags.add(HomeFragment::class.java.name)
tags.add(TrucksFragment::class.java.name)
tags.add(UserFragment::class.java.name)
fragments.clear()
fragments.add(JournalFragment())
fragments.add(WaitingFragment())
fragments.add(HomeFragment())
fragments.add(TrucksFragment())
fragments.add(UserFragment())
}
}
至此墓塌,activity意外銷毀導(dǎo)致的Fragment重疊問題已經(jīng)完美解決瘟忱,哦,還好漏了一個(gè)點(diǎn)苫幢,如何模擬activity銷毀并支持debug,其實(shí)很簡(jiǎn)單访诱,一張圖片教會(huì)你
只需要在開發(fā)者模式下打開不保留活動(dòng)的開關(guān),就可以了
本文寫的有些粗糙韩肝,如果有不當(dāng)之處盐数,歡迎指正