Using Fragment inside Navigation Fragment

32 views Asked by At

Codes

Main Activity

// MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
<!-- activity_main.xml -->

<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

Home Fragment (for home page)

// HomeFragment.kt

class HomeFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = super.onCreateView(inflater, container, savedInstanceState)

        // init appbar
        var toolbarTitle = view?.findViewById<TextView>(R.id.toolbar_title)
        toolbarTitle?.text = resources.getString(R.string.app_name)

        // init route selection
        val routeSelectionFragment = RouteSelectionFragment(
            Route(Station.Konak, Station.Karsiyaka, Day.Monday)
        )
        requireActivity().supportFragmentManager.beginTransaction().apply {
            replace(R.id.fragmentContainer, routeSelectionFragment)
            commit()
        }

        return view;
    }
}
<!-- fragment_home.xml -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        >
        <TextView
            android:id="@+id/toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
            android:textColor="@color/white"
            android:layout_gravity="center" />
    </androidx.appcompat.widget.Toolbar>

    <FrameLayout
        android:id="@+id/fragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

    </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Route Selection Fragment (as custom bottom navbar)

// RouteSelectionFragment.kt

class RouteSelectionFragment(
    private val route: Route,
) : Fragment(R.layout.fragment_route_selection) {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val startStationText = getView()?.findViewById<TextView>(R.id.startStationText)
        val endStationText = getView()?.findViewById<TextView>(R.id.endStationText)
        val dayText = getView()?.findViewById<TextView>(R.id.dayText)

        val dayString = resources.getString(
            resources.getIdentifier(
                route.day.nameId,
                "string",
                context?.packageName
            )
        )

        startStationText?.text = route.startStation.name
        endStationText?.text = route.endStation.name
        dayText?.text = dayString
    }
}
<!-- fragment_route_selection.xml -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:padding="16dp"
    tools:context=".RouteSelectionFragment">

    <TextView
        android:id="@+id/startStationText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="---"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/imageView"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:src="@drawable/baseline_arrow_right_alt_24"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/endStationText"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/startStationText"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/endStationText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="---"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/imageView3"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:src="@drawable/baseline_alternate_email_24"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/dayText"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/endStationText"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/dayText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="---"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/imageView3"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Description

I've been trying to learn native Android and testing stuff out. Normally, I've had my MainActivity as my home page and I was using RouteSelectionFragment as a bottom app bar.

While I was studying how navigation works in native Android, I've come across navigation components (mainly this video).

So, I thought it would be reasonable to move all home representation to its own HomeFragment using navigation components. It is the only navigation fragment I have in the project right now.

But, then, when I launch the app, I get this error from logcat on runtime:

   com.erayerdin.izmirferry             E  FATAL EXCEPTION: main
                                                                                                    Process: com.erayerdin.izmirferry, PID: 10751
                                                                                                    java.lang.IllegalArgumentException: No view found for id 0x7f0800c2 (com.erayerdin.izmirferry:id/fragmentContainer) for fragment RouteSelectionFragment{154b91b} (28b4afc2-7d5e-4594-88d4-2ffd409755b0 id=0x7f0800c2)
                                                                                                        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:514)
                                                                                                        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
                                                                                                        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1890)
                                                                                                        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1808)
                                                                                                        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1751)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2976)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2886)
                                                                                                        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
                                                                                                        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:351)
                                                                                                        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
                                                                                                        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1543)
                                                                                                        at android.app.Activity.performStart(Activity.java:8330)
                                                                                                        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3670)
                                                                                                        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
                                                                                                        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                        at android.os.Looper.loop(Looper.java:288)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7872)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

Clearly, there's something I don't understand about how fragments work. I've tried a couple of things I've seen here, including childFragmentManager and parentFragmentManager.

1

There are 1 answers

0
Progressier On
  1. In your Activity use FrameLayout instead androidx.fragment.app.FragmentContainerView. Don't forget give it an id. In your case better way to call it "fragmentContainer".
  2. You should organize navigation in Activity. Move this code out from HomeFragment to Activity and call it, when user interacts with screen's navigation bar:

code from fragment:

// init route selection
val routeSelectionFragment = RouteSelectionFragment(
    Route(Station.Konak, Station.Karsiyaka, Day.Monday)
)
requireActivity().supportFragmentManager.beginTransaction().apply {
     replace(R.id.fragmentContainer, routeSelectionFragment)
     commit()
}

move to activity:

// init route selection
val routeSelectionFragment = RouteSelectionFragment(
    Route(Station.Konak, Station.Karsiyaka, Day.Monday)
)
supportFragmentManager.beginTransaction().apply {
     replace(R.id.fragmentContainer, routeSelectionFragment)
     commitAllowingStateLoss() // <-- I recommend to use this method
}

Also you can remove fragmentContainer from HomeFragment