SafeArgs is a gradle plugin that allows you to Pass data to destination UI components. It generates simple object and builder classes for type-safe navigation and access to any associated arguments. Safe Args is strongly recommended for navigating and passing data because it ensures type-safety. A sample video is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Kotlin language.
Step by Step Implementation
Step 1: Create a new project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add dependency
Inside build.gradle (project) add the following code under dependencies.
dependencies {
classpath “androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2”
}
Inside build.gradle (app) add the following code and click Sync now
plugins {
id ‘com.android.application’
id ‘kotlin-android’
id ‘kotlin-android-extensions’
id “androidx.navigation.safeargs.kotlin”
}
Step 3: Create two new Fragments
In this article, we are going to send data from one fragment and receive it in another. So, First, create two Fragments. To create a new Fragment:
Project Name (right click) -> new -> Fragment -> Fragment (Blank)
A dialog box will open. In the Fragment Name write Registration and in fragment layout name write fragment_registration. In a similar way create another fragment with fragment name Detail and fragment layout name as fragment_detail.
Step 4: Create an XML layout of both fragments
Go to the Fragment_registration.xml file and refer to the following code. Below is the code for the Fragment_registration.xml file. This is for the basic layout used in the app.
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".Registration" >
< EditText
android:id = "@+id/et_name"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_alignParentStart = "true"
android:layout_alignParentEnd = "true"
android:layout_margin = "20dp"
android:ems = "10"
android:hint = "Name"
android:inputType = "textPersonName"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
< EditText
android:id = "@+id/et_email"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:ems = "10"
android:hint = "Email"
android:layout_margin = "20dp"
android:inputType = "textPersonName"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/et_name" />
< EditText
android:id = "@+id/et_password"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:ems = "10"
android:hint = "Password"
android:layout_margin = "20dp"
android:inputType = "textPersonName"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/et_email" />
< Button
android:id = "@+id/button_send"
android:layout_width = "276dp"
android:layout_height = "50dp"
android:text = "Send"
android:layout_margin = "20dp"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/et_password" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Go to the Fragment_detail.xml file and refer to the following code. Below is the code for the Fragment_detail.xml file.
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".Details" >
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Name :"
android:id = "@+id/tv1"
android:textSize = "20sp"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
android:layout_marginTop = "50dp"
android:layout_marginStart = "30dp"
/>
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:textColor = "@color/black"
android:id = "@+id/tv_name"
app:layout_constraintLeft_toRightOf = "@id/tv1"
app:layout_constraintTop_toTopOf = "@id/tv1"
android:layout_marginStart = "20dp"
/>
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Email :"
android:id = "@+id/tv2"
android:textSize = "20sp"
app:layout_constraintTop_toBottomOf = "@id/tv1"
app:layout_constraintLeft_toLeftOf = "parent"
android:layout_marginTop = "20dp"
android:layout_marginStart = "30dp"
/>
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:textColor = "@color/black"
android:id = "@+id/tv_email"
app:layout_constraintLeft_toRightOf = "@id/tv2"
app:layout_constraintTop_toTopOf = "@id/tv2"
android:layout_marginStart = "20dp"
/>
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Password :"
android:id = "@+id/tv3"
android:textSize = "20sp"
app:layout_constraintTop_toBottomOf = "@id/tv2"
app:layout_constraintLeft_toLeftOf = "parent"
android:layout_marginTop = "20dp"
android:layout_marginStart = "30dp"
/>
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:textColor = "@color/black"
android:id = "@+id/tv_password"
app:layout_constraintLeft_toRightOf = "@id/tv3"
app:layout_constraintTop_toTopOf = "@id/tv3"
android:layout_marginStart = "20dp"
/>
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Step 5: Create a new Kotlin class
Create a new Class User.kt we will use data of custom generic “User” having a name, email, password to pass to another fragment.
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize data class User(
val name : String = "" ,
val email : String= "" ,
val password : String = ""
) : Parcelable |
Step 6: Create a new Navigation graph
res (right click) -> new -> Android resource file
In the dialog write file name as nav_graph and choose Resource type as “Navigation“. and click Ok. Now open the just created nav_graph.xml file click on the new destination icon and choose both of the fragments. Make Fragment_registration as the home. Create action from fragment_registration to fragment_detail and pass the User argument in the arguments of Fragment_detail. Its XML code is given below.
<? xml version = "1.0" encoding = "utf-8" ?>
< navigation
android:id = "@+id/nav_graph"
app:startDestination = "@id/registration" >
< fragment
android:id = "@+id/registration"
android:name = "com.geeksforgeeks.navargsexample.Registration"
android:label = "fragment_registration"
tools:layout = "@layout/fragment_registration" >
< action
android:id = "@+id/action_registration_to_details"
app:destination = "@id/details" />
</ fragment >
< fragment
android:id = "@+id/details"
android:name = "com.geeksforgeeks.navargsexample.Details"
android:label = "fragment_details"
tools:layout = "@layout/fragment_details" >
< argument
android:name = "user"
app:argType = "com.geeksforgeeks.navargsexample.User" />
</ fragment >
</ navigation >
|
Step 7: Working with the activity_main.xml file
Go to the activity_main.xml file and refer to the following code. Below is the code for the activity_main.xml file. This layout contains one Frame Layout and a fragment that will act as a host for the fragments that we created earlier. Notice the navGraph tag inside the fragment tag.
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity" >
< FrameLayout
android:id = "@+id/frameLayout"
android:layout_width = "match_parent"
android:layout_height = "0dp"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.5"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" >
<!--this fragmnet will act as the host for
both fragments in the main activity-->
< 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/nav_graph"
/>
</ FrameLayout >
</ androidx.constraintlayout.widget.ConstraintLayout >
|
Step 8: Working with Registration.kt file
Go to the Registration.kt file and refer to the following code. Below is the code for the Registration.kt file. Comments are added inside the code to understand the code in more detail.
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.geeksforgeeks.navargsexample.databinding.FragmentRegistrationBinding
class Registration : Fragment() {
private var _binding: FragmentRegistrationBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRegistrationBinding.inflate(inflater, container, false )
val view = binding.root
// call onClick on the SendButton
binding.buttonSend.setOnClickListener {
val name = binding.etName.text.toString()
val email = binding.etEmail.text.toString()
val password = binding.etPassword.text.toString()
// create user object and pass the
// required arguments
// that is name, email,and password
val user = User(name,email, password)
// create an action and pass the required user object to it
// If you can not find the RegistrationDirection try to "Build project"
val action = RegistrationDirections.actionRegistrationToDetails(user)
// this will navigate the current fragment i.e
// Registration to the Detail fragment
findNavController().navigate(
action
)
}
return view
}
override fun onDestroyView() {
super .onDestroyView()
_binding = null
}
} |
Step 9: Working with the Details.kt file
Go to the Details.kt file and refer to the following code. Below is the code for the Details.kt file. Comments are added inside the code to understand the code in more detail.
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.navArgs
import com.geeksforgeeks.navargsexample.databinding.FragmentDetailsBinding
class Details : Fragment() {
private var _binding: FragmentDetailsBinding? = null
private val binding get() = _binding!!
// get the arguments from the Registration fragment
private val args : DetailsArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDetailsBinding.inflate(inflater, container, false )
val view = binding.root
// Receive the arguments in a variable
val userDetails = args.user
// set the values to respective textViews
binding.tvName.text = userDetails.name
binding.tvEmail.text = userDetails.email
binding.tvPassword.text = userDetails.password
return view
}
override fun onDestroyView() {
super .onDestroyView()
_binding = null
}
} |
Note: In this example, we don’t have to write any code inside ActivityMain.kt
Output:
Github Repo here.