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
Toolbar
as the argument tosetSupportActionBar()
, theActionBar
assumes complete ownership of thatToolbar
and 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 theMenuHost
andMenuProvider
APIs.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:label
on 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 appropriatesetup
method ofNavigationUI
). This would remove the need to use your listener at all, thus allowing you to delete all of your code entirely.