文章目录
- 一、前言
- 二、理论概念
- 三、代码演示
- 四、参考链接
一、前言
以前Fragment、View里面没有返回事件,需要自己处理,目前官方提供了OnBackPressedDispatcher
对事件进行拦截处理,这个类也主要是处理这个问题
注意事项:OnBackPressedDispatcher
并不是对onBackPressed()
的替换,只是对它的补充,最终返回的话还是要使用onBackPressed()
二、理论概念
代码使用如下
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This callback will only be called when MyFragment is at least Started.
requireActivity().onBackPressedDispatcher.addCallback(
this,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d("YM", "handleOnBackPressed(): name=${tag}")
}
})
// The callback can be enabled or disabled here or in the lambda
}
...
}
OnBackPressedDispatcher
通过定义的先后顺序来进行触发。他们触发的先后顺序为倒叙方式。例如您按顺序添加了三个名为 one
、two
和 three
的回调,则它们的调用顺序分别为 three
、two
和 one
。
回调遵循责任链模式。责任链中的每个回调仅在前面的回调处于未启用状态时调用。这意味着,在前面的示例中,仅当 three
回调处于未启用状态时,系统才会调用 two
回调。仅当 two
回调处于未启用状态时,系统才会调用 one
回调,以此类推。
回调状态可以通过OnBackPressedDispatcher::setEnabled(boolean enabled)
动态启用。
需要注意的是官方推荐使用OnBackPressedCallback
来替换Activity::onBackPressed()
。但是有这么一个情况:
因为OnBackPressedDispatcher
最终是在Lifecycle.Event.ON_START
事件收到后进行注册的。表现在生命周期中为onStart()
函数。但是据Android10.0版本的手机测试,其Activity::onStart()
执行会在Fragment::onStart()
之后。因此,在OnBackPressedDispatcher
栈中的顺序中Activity
会为最后。所以这样在Activity
和Fragment
嵌套使用的时候,会只能收到Activity
的返回拦截事件。除非Fragment
的添加是在Activity::onStart()
函数之后进行添加的。但是在Android8.0测试则是先执行Activity,后执行Fragment。这样的话,程序就很正常了
三、代码演示
这里定义一个页面来演示下该功能,每次点击返回键就返回移除该Fragment
。整体页面如下:
这个页面由两个Fragment
组成。代码如下:
fragment_call_back.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CallBackFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
</FrameLayout>
CallBackFragment.kt
package com.hello.world
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
class CallBackFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(
this,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d("YM", "handleOnBackPressed(): name=${tag}")
closeFragment()
}
})
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_call_back, container, false)
}
private fun closeFragment() = requireActivity().supportFragmentManager.beginTransaction()
.remove(this).commit()
}
activity_call_back.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CallBackActivity">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/call_back_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:tag="fragment1"
android:name="com.hello.world.CallBackFragment"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/call_back_container_2"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/call_back_container_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:tag="fragment2"
android:name="com.hello.world.CallBackFragment"
app:layout_constraintTop_toBottomOf="@+id/call_back_container"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
CallBackActivity.kt
class CallBackActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_call_back)
}
}
四、参考链接
- 提供自定义返回导航
https://developer.android.com/guide/navigation/navigation-custom-back?hl=zh-cn - Android | Jetpack 处理回退事件的新姿势 —— OnBackPressedDispatcher
https://www.jianshu.com/p/75bc5108628f