個人原創(chuàng),轉(zhuǎn)載請注明出處:http://m.itdecent.cn/p/aec2cde0a5f0
Jetpack組件Navigation為Fragment添加了自動的返回棧管理,非常便于處理多個Fragment的相互跳轉(zhuǎn)。但Fragment默認沒有onBackPressed()方法,在按下返回鍵時無法處理除Fragment出棧以外的其他操作。下面給出幾種Fragment里監(jiān)聽返回鍵代碼,順便探討下該事件的最佳寫法。
1. 給onBackPressedDispatcher添加回調(diào)
requireActivity().onBackPressedDispatcher
.addCallback(viewLifecycleOwner, object: OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
//Handle back event from any fragment
}
})
這個方法的最大弊病是不能在里面調(diào)用Activity的onBackPressed()(會產(chǎn)生循環(huán)),當Fragment不需要處理返回操作時不能向上傳遞到Activity,必須在Fragment里處理包括Activity在內(nèi)的所有返回鍵操作,這對于Fragment的編寫者來說很不友好,于是很快被我放棄了。我們希望Activity和Fragment各自的邏輯代碼能分離開來。
2. 給rootView設(shè)置一個OnKeyListener來監(jiān)聽key事件
mRootView.setFocusable(true);
mRootView.setFocusableInTouchMode(true);
mRootView.setOnKeyListener { v, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (condition) {
...
}else {
activity.onBackPressed()
}
true
}
false
}
這段代碼基本上能滿足大部分要求,Activity和Fragment分別處理各自的返回操作,但任然有兩個小問題。一是要在Fragment里獲取到RootView,二是如果Activity和Fragment都需要對返回鍵做出反應(yīng),那么必須是優(yōu)先觸發(fā)Fragment的返回操作,而Activity不知道返回操作什么時候會被Fragment攔截?。ó斎灰部梢栽贔ragment里增加對Activity里元素的監(jiān)聽,但那樣就違背了二者操作邏輯相互分離的初衷)
3. 給Fragment編寫各自的onBackPressed()方法并在Activity的onBackPressed()里調(diào)用
乍一看,這樣每次都要在Activity的onBackPressed()里判斷當前是哪一個Fragment,并且還要判斷該Fragment是否需要處理返回事件,這不是給Activity添麻煩么?其實不然,通過將給BaseFragment基類(如果沒有就寫一個)添加onBackPressed()方法這些都可以交給各Fragment自己完成。來看BaseFragment:
abstract class BaseFragment : Fragment() {
...
protected val activity by lazy { getActivity() as MainActivity }
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
...
activity.currentFragment = this //currentFragment是Activity里定義的變量,用來持有當前Fragment
}
/**fragment攔截返回鍵返回true,不攔截返回false*/
abstract fun onBackPressed(): Boolean
}
子類Fragment:
class ChildFragment : BaseFragment() {
...
protected val activity by lazy { getActivity() as MainActivity }
override fun onBackPressed(): Boolean {
if (condition) {
...
return true //返回true表示消耗掉返回事件,Activity不再處理
}else {
return false //返回false不處理返回事件,交給Activity處理
}
}
}
Activity:
class MainActivity : AppCompatActivity() {
lateinit var currentFragment : BaseFragment
...
override fun onBackPressed() {
when {
currentFragment.onBackPressed() -> {} /*Fragment處理了返回操作返回true,不再執(zhí)行其他代碼
Fragment不處理返回false,此時Activity里的其他代碼發(fā)揮作用*/
condition -> { ... }
else -> super.onBackPressed()
}
}
}
這里用到了Java的動態(tài)綁定,通過在BaseFragment里獲取到當前Fragment的實例以及子Fragment重寫B(tài)aseFragment的onBackpressed()方法,使得Activity能自動調(diào)用當前Fragment的onBackpressed()方法。這種寫法我認為是最優(yōu)的,實現(xiàn)了Activity與Fragment返回邏輯代碼的完全分離,Activity不需要知道Fragment具體干了什么,只需要知道結(jié)果(是否消耗掉事件),并且能通過調(diào)整condition的順序來調(diào)整Activity與Fragment返回操作的優(yōu)先級。唯一的缺點可能就是多了點代碼量。
如果你有更好的寫法,歡迎留言指出!