2

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

SplashFragment -> Fragment1 -> Fragment2

Following is the storyboard(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">

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 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 line 51 is:

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

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?

Edit 1:

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"/>

And in MainActivity override onBackPressed as follows:

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

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.

4

3 回答 3

2

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

问题是,我正在观察一个MutableLiveData来自ViewModel并基于它的价值的导航正在发生。但我不知道片段的生命周期所有者倾向于破坏观察者并根据视图生命周期重新实例化它以避免泄漏。因此,一旦导航发生,观察者就不再存在,导航代码在观察者之内。导航返回时需要相同的代码,因此在尝试访问它时,代码会崩溃。

我通过在需要完成导航时使用接口给片段回调来解决了这个问题。

于 2019-05-09T05:04:21.477 回答
0

您的错误日志是说您正在使用 navcontroller 调用操作 id 为 action_splashFragment_to_registerMSISDNFragment 的操作。尝试找到该操作 ID 并检查它是否有效。也使用app:popUpTo="@id/splashFragment" app:popUpToInclusive="true"in action_splashFragment_to_fragment1代替action_fragment1_to_fragment2. 这将从后台堆栈中删除飞溅片段。这是代码片段:

<?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"
                app:popUpTo="@id/splashFragment"
                app:popUpToInclusive="true" />
        </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: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>
于 2019-04-25T12:16:30.537 回答
0

导航到新片段后,我刚刚删除了观察者。像这样:

myLiveData.removeObservers(this)

于 2019-07-30T09:19:47.540 回答