I'm using navigation components and bottomNavigationView together. When I switch the tabs back and forth many times, then I got crash message:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5361)
at android.view.ViewGroup.addView(ViewGroup.java:5190)
at android.view.ViewGroup.addView(ViewGroup.java:5162)
at androidx.appcompat.widget.Toolbar.addSystemView(Toolbar.java:1528)
at androidx.appcompat.widget.Toolbar.setTitle(Toolbar.java:777)
at com.atp.newarchitecture.activity.AppActivity.onCreate$lambda-0(AppActivity.kt:119)
The code is:
navController.addOnDestinationChangedListener { _,
destination,
argument ->
binding.toolbar.title = resources.getString(when (destination.id) {
R.id.fragmentId -> R.string.fragmentTitle
//... more ids
})
the layout file is:
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@ id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ToolBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="?attr/homeAsUpIndicator" />
<TextView
android:id="@ id/selected_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/login_text_input_layout"
app:layout_constraintBottom_toBottomOf="@ id/toolbar"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1"
tools:text="@string/selected_count" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@ id/alert_tip_root"
android:layout_width="0dp"
android:layout_height="@dimen/quadruple_margin"
android:layout_margin="@dimen/default_margin"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@ id/bottom_navigation_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
android:theme="@style/BottomNavigationTheme"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_bar" />
<androidx.fragment.app.FragmentContainerView
android:id="@ id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@id/bottom_navigation_view"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:navGraph="@navigation/nav_graph" />
<View
android:id="@ id/loading_background_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
I know the crash message means one view should only has a parent, but seems no addView here. Wondering if every time binding.root.title assign call addView? Any help? Thanks!
EDIT:
def nav_version = "2.3.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
implementation("androidx.navigation:navigation-compose:2.4.0-beta02")
CodePudding user response:
As explained in the Navigation UI guide:
Caution: If you pass a
Toolbaras the argument tosetSupportActionBar(), theActionBarassumes complete ownership of thatToolbarand you must not use any Toolbar APIs after that call.
This is true in every case where you call setSupportActionBar(). This means that directly calling any Toolbar API, such as setTitle, is going to break that ownership contract and lead to these kind of exceptions.
Instead, you should either:
Don't use
setSupportActionBar()at all. You can connect a Toolbar to Navigation directly and upgrade to AppCompat 1.4.0 to have fragments add elements to the Toolbar via theMenuHostandMenuProviderAPIs.If you use
setSupportActionBar(), then you need to set the title via the ActionBar APIs. Namely, callingsupportActionBar!!.title = ...Follow the app bar guide and set an
android:labelon each destination in your navigation graph XML file (i.e.,android:label="@string/fragmentTitle"). This will automatically update the title as the current destination changes (assuming you've called the appropriatesetupmethod ofNavigationUI). This would remove the need to use your listener at all, thus allowing you to delete all of your code entirely.
