Android 导航组件后退按钮不起作用

Chr*_*ona 17 android android-fragments android-navigation

我在 android 中使用导航组件,我最初设置了 6 个片段。问题是当我添加一个新片段 (ProfileFragment) 时。

当我从开始目的地导航到这个新片段时,按下本机后退按钮不会弹出当前片段。相反,它只停留在我所在的片段中——后退按钮什么也不做。

这是我的navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/dashboard_navigation"
    app:startDestination="@id/dashboardFragment"
    >

                <fragment
                    android:id="@+id/dashboardFragment"
                    android:name="com.devssocial.localodge.ui.dashboard.ui.DashboardFragment"
                    android:label="DashboardFragment"
                    >
                                <action
                                    android:id="@+id/action_dashboardFragment_to_newPostFragment"
                                    app:destination="@id/newPostFragment"
                                    app:enterAnim="@anim/slide_in_up"
                                    app:exitAnim="@anim/slide_out_down"
                                    app:popEnterAnim="@anim/slide_in_up"
                                    app:popExitAnim="@anim/slide_out_down"
                                    />
                                <action
                                    android:id="@+id/action_dashboardFragment_to_notificationsFragment"
                                    app:destination="@id/notificationsFragment"
                                    app:enterAnim="@anim/slide_in_up"
                                    app:exitAnim="@anim/slide_out_down"
                                    app:popEnterAnim="@anim/slide_in_up"
                                    app:popExitAnim="@anim/slide_out_down"
                                    />
                                <action
                                    android:id="@+id/action_dashboardFragment_to_mediaViewer"
                                    app:destination="@id/mediaViewer"
                                    app:enterAnim="@anim/slide_in_up"
                                    app:exitAnim="@anim/slide_out_down"
                                    app:popEnterAnim="@anim/slide_in_up"
                                    app:popExitAnim="@anim/slide_out_down"
                                    />
                                <action
                                    android:id="@+id/action_dashboardFragment_to_postDetailFragment"
                                    app:destination="@id/postDetailFragment"
                                    app:enterAnim="@anim/slide_in_up"
                                    app:exitAnim="@anim/slide_out_down"
                                    app:popEnterAnim="@anim/slide_in_up"
                                    app:popExitAnim="@anim/slide_out_down"
                                    />

                            ====================== HERE'S THE PROFILE ACTION ====================                                
                                <action
                                    android:id="@+id/action_dashboardFragment_to_profileFragment"
                                    app:destination="@id/profileFragment"
                                    app:enterAnim="@anim/slide_in_up"
                                    app:exitAnim="@anim/slide_out_down"
                                    app:popEnterAnim="@anim/slide_in_up"
                                    app:popExitAnim="@anim/slide_out_down"
                                    />
                            =====================================================================                                

                </fragment>



                <fragment
                    android:id="@+id/profileFragment"
                    android:name="com.devssocial.localodge.ui.profile.ui.ProfileFragment"
                    android:label="fragment_profile"
                    tools:layout="@layout/fragment_profile"
                    />
</navigation>
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

在上图中,突出显示的箭头(左侧)是我遇到问题的导航操作。

在我的Fragment代码中,我导航如下:

findNavController().navigate(R.id.action_dashboardFragment_to_profileFragment)
Run Code Online (Sandbox Code Playgroud)

其他导航操作按预期工作。但是由于某种原因,这个新添加的片段没有按预期运行。

当我导航到 ProfileFragment 和按下后退按钮时,没有显示日志。

我错过了什么吗?或者我的动作/片段配置有什么问题?

编辑:我不在ProfileFragment 中做任何事情。这是它的代码:

class ProfileFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_profile, container, false)
    }


}
Run Code Online (Sandbox Code Playgroud)

我的活动 xml包含导航主机:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <fragment
            android:id="@+id/dashboard_navigation"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:navGraph="@navigation/dashboard_navigation"
            app:defaultNavHost="true"/>

</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

trO*_*k12 32

对于在前一个 Fragment(即 Home Fragment)中使用 LiveData 的任何人,每当您通过按后退按钮返回前一个 Fragment 时,Fragment 开始观察数据,并且因为 ViewModel 在此操作中幸存下来,它会立即发出最后发出的值,在我的case 打开我按下后退按钮的 Fragment,这样看起来后退按钮不起作用,解决方案是使用只发出一次数据的东西。我用过这个:

class SingleLiveData<T> : MutableLiveData<T>() {

private val pending = AtomicBoolean()

/**
 * Adds the given observer to the observers list within the lifespan of the given
 * owner. The events are dispatched on the main thread. If LiveData already has data
 * set, it will be delivered to the observer.
 *
 * @param owner The LifecycleOwner which controls the observer
 * @param observer The observer that will receive the events
 * @see MutableLiveData.observe
 */
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
    super.observe(owner, Observer { t ->
        if (pending.compareAndSet(true, false)) {
            observer.onChanged(t)
        }
    })
}

/**
 * Sets the value. If there are active observers, the value will be dispatched to them.
 *
 * @param value The new value
 * @see MutableLiveData.setValue
 */
@MainThread
override fun setValue(value: T?) {
    pending.set(true)
    super.setValue(value)
}
Run Code Online (Sandbox Code Playgroud)


nir*_*rma 28

如果您在导航组件中使用 setupActionBarWithNavController 例如:

 setupActionBarWithNavController(findNavController(R.id.fragment))
Run Code Online (Sandbox Code Playgroud)

然后还在您的主要活动中覆盖和配置此方法:

 override fun onSupportNavigateUp(): Boolean {
    val navController = findNavController(R.id.fragment)
    return navController.navigateUp() || super.onSupportNavigateUp()
}
Run Code Online (Sandbox Code Playgroud)

我的主活动.kt

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    setupActionBarWithNavController(findNavController(R.id.fragment))
}

override fun onSupportNavigateUp(): Boolean {
    val navController = findNavController(R.id.fragment)
    return navController.navigateUp() || super.onSupportNavigateUp()
}
}
Run Code Online (Sandbox Code Playgroud)


Rak*_*mar 9

您可以将以下内容用于 Activity

onBackPressedDispatcher.addCallback(
                this,
                object : OnBackPressedCallback(true) {
                    override fun handleOnBackPressed() {
                        onBackPressed()
                        // if you want onBackPressed() to be called as normal afterwards

                    }
                }
        )
Run Code Online (Sandbox Code Playgroud)

对于fragment,它将requireActivity()与回调一起需要

requireActivity().onBackPressedDispatcher.addCallback(
                    this,
                    object : OnBackPressedCallback(true) {
                        override fun handleOnBackPressed() {
                            requireActivity().onBackPressed()
                            // if you want onBackPressed() to be called as normal afterwards

                        }
                    }
            )
Run Code Online (Sandbox Code Playgroud)

如果你有一个Button或其他东西来执行一个动作,那么你可以使用

this.findNavController().popBackStack()
Run Code Online (Sandbox Code Playgroud)

  • 你绝对不应该从 `OnBackPressedCallback` 调用 `onBackPressed()` - 这肯定会导致无限循环。无论如何,“NavController”都会设置自己的“OnBackPressedCallback”,您不需要这样做。 (7认同)
  • 这将是需要的。在“onBackPressed()”上执行特定任务 (2认同)
  • 从片段调用“requireActivity().onBackPressed()”会导致“无限循环”并且应用程序崩溃。 (2认同)

小智 7

我使用MutableLiveData在片段之间导航时发生了这个问题,并且正在观察多个片段的实时数据对象。

我通过仅观察实时数据对象一次或使用SingleLiveEvent而不是MutableLiveData. 因此,如果您在这里遇到相同的情况,请尝试仅观察实时数据对象一次或使用SingleLiveEvent.