Android Jetpack Navigation: Load Activity/Fragment With SafeArgs and Parcelable (Kotlin)

Apr 19, 2020

NOTE: If you have yet to setup jetpack navigation, refer to Android Setup Jetpack Navigation (Kotlin).

Setup

NOTE: Refer https://developer.android.com/jetpack/androidx/releases/navigation

Edit top level / project build.gradle

buildscript {
    ext {
        nav_version = '2.3.0-alpha05'
    }
    repositories {
        google()
        // ...
    }
    dependencies {
        // ...
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

Edit project / module build.gradle

apply plugin: "androidx.navigation.safeargs.kotlin"

dependencies {
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

Create Fragment

class BatchFragment : Fragment() {    // private val viewModel: BatchViewModel by viewModels()    val args: BatchFragmentArgs by navArgs()    override fun onCreateView(        inflater: LayoutInflater, container: ViewGroup?,        savedInstanceState: Bundle?    ): View? {        return inflater.inflate(R.layout.batch, container, false)    }    override fun onActivityCreated(savedInstanceState: Bundle?) {        super.onActivityCreated(savedInstanceState)        if (args.default.isNew) {            textView.text = "New Batch"        }        else {            textView.text = "Batch Id = ${args.default.id}"        }    }}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.sub.BatchFragment">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello" />

</FrameLayout>

Create BatchArgs Class as Args

@Parcelizeclass BatchArgs(val id: String? = null): Parcelable {    val isNew: Boolean        get() = id == null}

NOTE: I prefer to use Parcelable as arguments as I don't have to edit navigation graph for any modification, and it support more complex structure.

Edit Navigagation Graph

Click New Destination icon, select fragment.

  • Id: batchNav
  • Label: Batch

At Arguments -> Add Component

  • name: default
  • type: Custom Parcelable -> Select BatchArgs

Click Add

Drag a path from TestFragment to BatchFragment.

  • id: action_testNav_to_batchNav
  • destination: batchNav
<?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/mobile_navigation"
    app:startDestination="@+id/testNav">

    <fragment
        android:id="@+id/testNav"
        android:name="com.luasoftware.garden.view.TestFragment"
        android:label="@string/title_test"
        tools:layout="@layout/test" >
        <action
            android:id="@+id/action_testNav_to_batchNav"
            app:destination="@id/batchNav" />
    </fragment>
    <fragment
        android:id="@+id/batchNav"
        android:name="com.luasoftware.garden.view.sub.BatchFragment"
        android:label="Batch"
        tools:layout="@layout/batch" >
        <argument
            android:name="default"
            app:argType="com.luasoftware.garden.model.args.BatchArgs" />
    </fragment>
</navigation>
class TestFragment : Fragment() {    override fun onCreateView(            inflater: LayoutInflater,            container: ViewGroup?,            savedInstanceState: Bundle?    ): View? {        return inflater.inflate(R.layout.test, container, false)    }    override fun onActivityCreated(savedInstanceState: Bundle?) {        super.onActivityCreated(savedInstanceState)        testButton.setOnClickListener {            val args = BatchArgs(id = "abc")            val action = TestFragmentDirections.actionTestNavToBatchNav(args)            findNavController().navigate(action)        }    }}
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.TestFragment">

    <Button
        android:id="@+id/testButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Test"
         />

</LinearLayout>

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.