Android Navcontroller硬件后退按钮崩溃 [英] Android Navcontroller hardware back button crash

查看:571
本文介绍了Android Navcontroller硬件后退按钮崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用新的Android故事板创建应用程序。流程应如下所示:

I am using new android storyboard to create an application. The flow need to be like following:


SplashFragment-> Fragment1-> Fragment2

SplashFragment -> Fragment1 -> Fragment2

以下是故事板( navigation_main.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/launch_navigation_graph"
            app:startDestination="@id/splashFragment">

    <fragment android:id="@+id/splashFragment" android:name="com.myapp.android.SplashFragment"
              android:label="fragment_splash" tools:layout="@layout/fragment_splash">
        <action android:id="@+id/action_splashFragment_to_fragment1"
                app:destination="@id/fragment1"/>
    </fragment>
    <fragment android:id="@+id/fragment1"
              android:name="com.myapp.android.Fragment1"
              android:label="fragment1" tools:layout="@layout/fragment_register_msisdn">
        <action android:id="@+id/action_fragment1_to_fragment2"
                app:destination="@id/fragment2" app:popUpTo="@+id/fragment1"
                app:enterAnim="@anim/nav_default_pop_enter_anim" app:exitAnim="@anim/nav_default_pop_exit_anim"/>
    </fragment>
    <fragment android:id="@+id/fragment2"
              android:name="com.myapp.android.Fragment2"
              android:label="fragment_fragment2" tools:layout="@layout/fragment_fragment2"/>
</navigation>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="MainActivity">

    <fragment
            android:id="@+id/mainNavigationHostFragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/navigation_main" />

</androidx.constraintlayout.widget.ConstraintLayout>

应用主题没有操作栏,因为我不想显示操作栏:

App Theme is withou t action bar since I don't want the actionbar to show up:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

基本上我需要 Fragment1 Fragment2 导航,然后按硬件后退按钮,返回到 Fragment1 。要从 Fragment1 导航到 Fragment2 ,我在Fragment1中有以下代码:

Basically I need a Fragment1 to Fragment2 navigation and then on hardware back button press, back to Fragment1. To navigate from Fragment1 to Fragment2, I have the following code in Fragment1:

findNavController().navigate(R.id.action_fragment1_to_fragment2)

SplashFragment 不应保留在堆栈中,因为在第一次启动时不需要。这就是为什么我仅在 Fragment1 Fragment2 中具有 popTo 的原因行动。但是在运行完相同代码后,从 Fragment2 按下,第一次不执行任何操作(不弹出),第二次由于以下异常而崩溃:

SplashFragment should not be maintained in the stack, since it is not required after first time showing in launch. That is why I have popTo only in Fragment1 to Fragment2 action. But after running the same, pressing back from Fragment2, for the first time does nothing(doesn't pop) and the second time, it crashes with the following exception:

2019-04-25 16:52:43.841 28598-28598/com.selfcare.safaricom E/InputEventSender: Exception dispatching finished signal.
2019-04-25 16:52:43.842 28598-28598/com.selfcare.safaricom E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
2019-04-25 16:52:43.846 28598-28598/com.selfcare.safaricom E/MessageQueue-JNI: java.lang.IllegalArgumentException: navigation destination com.selfcare.safaricom:id/action_splashFragment_to_registerMSISDNFragment is unknown to this NavController
        at androidx.navigation.NavController.navigate(NavController.java:803)
        at androidx.navigation.NavController.navigate(NavController.java:744)
        at androidx.navigation.NavController.navigate(NavController.java:730)
        at androidx.navigation.NavController.navigate(NavController.java:718)
        at com.myapp.android.SplashFragment.handleLaunchStatus(SplashFragment.kt:51)
        at com.myapp.android.SplashFragment.access$handleLaunchStatus(SplashFragment.kt:16)
        at com.myapp.android.SplashFragment$attachLaunchObserver$1.onChanged(SplashFragment.kt:44)
        at com.myapp.android.SplashFragment$attachLaunchObserver$1.onChanged(SplashFragment.kt:16)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:126)
        at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:424)
        at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:376)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
        at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:188)
        at androidx.lifecycle.LiveData.observe(LiveData.java:185)
        at com.myapp.android.SplashFragment.attachLaunchObserver(SplashFragment.kt:43)
        at com.myapp.android.SplashFragment.onViewCreated(SplashFragment.kt:35)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:895)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2092)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1866)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1822)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:298)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:241)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:288)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:241)
        at androidx.fragment.app.FragmentActivity$1.handleOnBackPressed(FragmentActivity.java:144)
        at androidx.activity.OnBackPressedDispatcher.onBackPressed(OnBackPressedDispatcher.java:136)
        at androidx.activity.ComponentActivity.onBackPressed(ComponentActivity.java:283)
        at android.app.Activity.onKeyUp(Activity.java:3083)
        at android.view.KeyEvent.dispatch(KeyEvent.java:2716)
        at android.app.Activity.dispatchKeyEvent(Activity.java:3366)
        at androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:80)
        at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:84)
        at androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:98)
        at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:558)
        at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:59)
        at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDelegateImpl.java:2736)
        at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:342)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:5037)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4905)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4585)
        at android.view.ViewRootImpl$InputStage.apply(Vie
2019-04-25 16:52:43.849 28598-28598/com.selfcare.safaricom E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.selfcare.safaricom, PID: 28598
    java.lang.IllegalArgumentException: navigation destination com.selfcare.safaricom:id/action_splashFragment_to_registerMSISDNFragment is unknown to this NavController
        at androidx.navigation.NavController.navigate(NavController.java:803)
        at androidx.navigation.NavController.navigate(NavController.java:744)
        at androidx.navigation.NavController.navigate(NavController.java:730)
        at androidx.navigation.NavController.navigate(NavController.java:718)
        at com.myapp.android.SplashFragment.handleLaunchStatus(SplashFragment.kt:51)
        at com.myapp.android.SplashFragment.access$handleLaunchStatus(SplashFragment.kt:16)
        at com.myapp.android.SplashFragment$attachLaunchObserver$1.onChanged(SplashFragment.kt:44)
        at com.myapp.android.SplashFragment$attachLaunchObserver$1.onChanged(SplashFragment.kt:16)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:126)
        at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:424)
        at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:376)
        at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
        at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:188)
        at androidx.lifecycle.LiveData.observe(LiveData.java:185)
        at com.myapp.android.SplashFragment.attachLaunchObserver(SplashFragment.kt:43)
        at com.myapp.android.SplashFragment.onViewCreated(SplashFragment.kt:35)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:895)
        at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2092)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1866)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1822)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:298)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:241)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:288)
        at androidx.fragment.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:241)
        at androidx.fragment.app.FragmentActivity$1.handleOnBackPressed(FragmentActivity.java:144)
        at androidx.activity.OnBackPressedDispatcher.onBackPressed(OnBackPressedDispatcher.java:136)
        at androidx.activity.ComponentActivity.onBackPressed(ComponentActivity.java:283)
        at android.app.Activity.onKeyUp(Activity.java:3083)
        at android.view.KeyEvent.dispatch(KeyEvent.java:2716)
        at android.app.Activity.dispatchKeyEvent(Activity.java:3366)
        at androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:80)
        at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:84)
        at androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:98)
        at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:558)
        at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:59)
        at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDelegateImpl.java:2736)
        at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:342)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:5037)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4905)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
2019-04-25 16:52:43.851 28598-28598/com.selfcare.safaricom E/AndroidRuntime:     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4585)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4642)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4618)
        at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4779)
        at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2571)
        at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:2081)
        at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:2072)
        at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2548)
        at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:326)
        at android.os.Looper.loop(Looper.java:160)
        at android.app.ActivityThread.main(ActivityThread.java:6718)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

SplashFragment 第51行是:

findNavController().navigate(R.id.action_splashFragment_to_fragment1)

如果我将popTo从 Fragment1 移至 Fragment2 操作,则此异常消失了,但是后退按钮也不起作用。我在这里做什么错了?

This exception is gone if I remove the popTo from Fragment1 to Fragment2 action, but then also the back button doesn't work. What am I doing wrong here?

编辑1:

根据Stavro Xhardha的评论,我对导航XML进行了一些修改:

As per Stavro Xhardha's comment, I made some modification to the navigation XML:


<fragment android:id="@+id/splashFragment" android:name="com.myapp.android.SplashFragment"
          android:label="fragment_splash" tools:layout="@layout/fragment_splash">
    <action android:id="@+id/action_splashFragment_to_fragment1"
            app:destination="@id/fragment1"
    app:popUpToInclusive="true" app:popUpTo="@+id/splashFragment"/> <!--Added this line -->
</fragment>
<fragment android:id="@+id/fragment1"
          android:name="com.myapp.android.Fragment1"
          android:label="fragment1" tools:layout="@layout/fragment_register_msisdn">
    <action android:id="@+id/action_fragment1_to_fragment2"
            app:destination="@id/fragment2" app:popUpTo="@+id/fragment1"/>
</fragment>
<fragment android:id="@+id/fragment2"
          android:name="com.myapp.android.Fragment2"
          android:label="fragment_fragment2" tools:layout="@layout/fragment_fragment2"/>

MainActivity 重写onBackPressed如下:

And in MainActivity override onBackPressed as follows:

override fun onBackPressed() {
    super.onBackPressed()
    if (!findNavController(R.id.launchNavigationHostFragment).navigateUp()) {
        finish()
    }
}

现在 Fragment2 弹出到 Fragment1 ,但随后在 Fragment1 上按回键,则会继续循环播放 Fragment1 。我无法退出该应用程序。

Now Fragment2 pops to Fragment1, but subsequent back press on Fragment1 keeps on bringing Fragment1 in a loop. I am not able to exit the app.

推荐答案

我终于设法找出问题并解决了。

I finally managed to figure out the issue and solved it.

问题是,我正在观察 ViewModel 中的 MutableLiveData 根据其值,导航正在进行中。但是我不知道片段的生命周期所有者倾向于破坏Observer并根据视图生命周期对其进行实例化以避免泄漏。因此,一旦导航发生,观察者就不再在那里,并且要导航的代码在观察者之内。导航时需要相同的代码,因此当尝试访问它时,代码将崩溃。

The issue was that, I was observing a MutableLiveData from ViewModel and based on its value the navigation was happening. But I was not aware that the life cycle owner of fragment tends to destroy the Observer and reinstantiate it based on view life cycle to avoid leaks. Hence once the navigation happens, the Observer is no longer there and the code to navigate is within the observer. The same code is required on navigating back, hence when trying to access it, the code crashes.

我通过使用接口为片段提供回调来解决此问题。导航需要完成。

I solved the issue by using an interface to give callback to fragment when the navigation needs to be done.

这篇关于Android Navcontroller硬件后退按钮崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆