Я использую новую раскадровку Android для создания приложения. Поток должен быть примерно таким:
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>
Тема приложения не содержит панель действий, поскольку я не хочу, чтобы панель действий отображалась:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
В основном мне нужна навигация от Fragment1
до Fragment2
, а затем при аппаратном нажатии кнопки возврата назад на Fragment1
. Для перехода от Fragment1
к Fragment2
у меня есть следующий код в Fragment1:
findNavController().navigate(R.id.action_fragment1_to_fragment2)
SplashFragment
не должен поддерживаться в стеке, так как он не требуется после первого показа при запуске. Вот почему у меня popTo
только в действии Fragment1
до Fragment2
. Но после запуска того же самого, нажав назад с Fragment2
, в первый раз ничего не происходит (не выдается), а во второй раз происходит сбой со следующим исключением:
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
, но тогда кнопка «Назад» также не будет работать. Что я тут не так делаю?
Редактировать 1:
Согласно комментарию Ставро Ксарды, я внес некоторые изменения в навигационный 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
переопределить onBack.
override fun onBackPressed() {
super.onBackPressed()
if (!findNavController(R.id.launchNavigationHostFragment).navigateUp()) {
finish()
}
}
Теперь Fragment2
отображается на Fragment1
, но последующее нажатие на Fragment1
продолжает возвращать Fragment1
в цикл. Я не могу выйти из приложения.