Jetpack Navigation预测返回手势取消后选抽屉项触发异常
我基于Jetpack Navigation实现了预测返回动画的简化Demo,抽屉关闭和Fragment切换时的预测返回手势动画均正常工作,但在取消返回操作(从FragmentTwo/FragmentThree滑动返回预览FragmentOne但未完成返回)后,点击抽屉菜单中的选项会触发崩溃。
重现步骤
- 从FragmentOne导航到FragmentTwo或FragmentThree
- 触发预测返回手势,滑动显示FragmentOne的预览状态后取消返回(不完成返回操作)
- 打开侧边抽屉菜单,点击任意Fragment选项,应用崩溃
崩溃日志
java.lang.IllegalArgumentException: saveBackStack("ebcca18f-eabb-424e-97b3-63de5fc97b85") must be self contained and not reference fragments from non-saved FragmentTransactions. Found reference to fragment FragmentOne{f7891b} (005b0355-e5f5-48d6-9ea8-df260bf6f4f4 id=0x7f080136 tag=1e300225-9207-4967-9e10-11f7bbd1ba65) in BackStackEntry{1ecf460 #4 ebcca18f-eabb-424e-97b3-63de5fc97b85} that were previously added to the FragmentManager through a separate FragmentTransaction. at androidx.fragment.app.FragmentManager.saveBackStackState(FragmentManager.java:2450) at androidx.fragment.app.FragmentManager$SaveBackStackState.generateOps(FragmentManager.java:3776) at androidx.fragment.app.FragmentManager.generateOpsForPendingActions(FragmentManager.java:2332) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1999) at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:702)
代码实现
MainActivity
class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration : AppBarConfiguration private lateinit var binding: MainActivityBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = MainActivityBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.toolbar) val host: NavHostFragment = supportFragmentManager .findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = host.navController appBarConfiguration = AppBarConfiguration( setOf(R.id.fragmentOne, R.id.fragmentTwo, R.id.fragmentThree), binding.drawerLayout) setupActionBarWithNavController(navController, appBarConfiguration) binding.navView.setupWithNavController(navController) } override fun onSupportNavigateUp(): Boolean { return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration) } }
FragmentOne
class FragmentOne: Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = FragmentSampleBinding.inflate(inflater, container, false).also { it.content.text = this::class.java.simpleName }.root }
FragmentTwo
class FragmentTwo : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = FragmentSampleBinding.inflate(inflater, container, false).also { it.content.text = this::class.java.simpleName }.root }
FragmentThree
class FragmentThree : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) = FragmentSampleBinding.inflate(inflater, container, false).also { it.content.text = this::class.java.simpleName }.root }
res/layout/main_activity.xml
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:openDrawer="start" tools:context="com.example.predictiveback.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" /> <fragment android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/mobile_navigation" /> </LinearLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="left" app:menu="@menu/nav_drawer_menu" /> </androidx.drawerlayout.widget.DrawerLayout>
res/layout/fragment_sample.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/content" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAlignment="center" android:textSize="52sp" /> </FrameLayout>
res/navigation/mobile_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" app:startDestination="@+id/fragmentOne"> <fragment android:id="@+id/fragmentOne" android:name="com.example.predictiveback.FragmentOne" android:label="Fragment One" tools:layout="@layout/fragment_sample"/> <fragment android:id="@+id/fragmentTwo" android:name="com.example.predictiveback.FragmentTwo" android:label="Fragment Two" tools:layout="@layout/fragment_sample"/> <fragment android:id="@+id/fragmentThree" android:name="com.example.predictiveback.FragmentThree" android:label="Fragment Three" tools:layout="@layout/fragment_sample"/> </navigation>
res/menu/nav_drawer_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@id/fragmentOne" android:icon="@drawable/ic_home" android:title="Fragment One" /> <item android:id="@id/fragmentTwo" android:icon="@drawable/ic_android" android:title="Fragment Two" /> <item android:id="@+id/fragmentThree" android:icon="@drawable/ic_android" android:title="Fragment Three" /> </menu>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="Predictive Back Demo" android:supportsRtl="true" android:theme="@style/AppTheme" android:enableOnBackInvokedCallback="true"> <activity android:name="com.example.predictiveback.MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <nav-graph android:value="@navigation/mobile_navigation" /> </activity> </application> </manifest>
依赖配置
ext { kotlinVersion = '2.0.0' appCompatVersion = "1.7.0" recyclerVersion = "1.3.2" materialVersion = "1.12.0" navigationVersion = '2.7.7' constraintLayoutVersion = "2.1.4" } dependencies { implementation "com.google.android.material:material:$rootProject.materialVersion" implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerVersion" implementation("androidx.drawerlayout:drawerlayout:1.2.0") implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion" implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion" implementation("androidx.activity:activity-ktx:1.9.1") implementation("androidx.fragment:fragment-ktx:1.8.2") implementation("androidx.transition:transition-ktx:1.5.1") }
内容的提问来源于stack exchange,提问作者ltp
相关产品推荐
相关产品推荐

