I have a fragment that can be either navigated to via a bottom navBar without arguments or from a different fragment with arguments. The navigation itself works perfectly fine but as soon as I add my arguments it crashes.
I'm unsure how much code is needed, so sorry if it's not complete:
This is my navigation fragment:
<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/navigation"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="fh.wfp2.flatlife.ui.views.HomeFragment"
android:label="Flatlife"
tools:layout="#layout/home_fragment" />
<fragment
android:id="#+id/todoFragment"
android:name="fh.wfp2.flatlife.ui.views.TodoFragment"
android:label="Todos">
<action
android:id="#+id/action_todoFragment_to_addTodoFragment"
app:destination="#id/addTodoFragment" />
<argument
android:name="taskname"
app:argType="string" />
<argument
android:name="isImportant"
app:argType="boolean" />
</fragment>
<fragment
android:id="#+id/addTodoFragment"
android:name="fh.wfp2.flatlife.ui.views.AddTodoFragment"
android:label="AddTodoFragment">
<action
android:id="#+id/action_addTodoFragment_to_todoFragment"
app:destination="#id/todoFragment" />
</fragment>
</navigation>
This is my addTodoFragment:
class AddTodoFragment : Fragment(R.layout.add_task_fragment) {
private lateinit var binding: AddTaskFragmentBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = AddTaskFragmentBinding.bind(view)
binding.bAddTodo.setOnClickListener {
if (binding.etAddTodo.text.isNotEmpty()) {
// viewModel.onAddTodoClicked(binding.etAddTodo.text.toString(),
binding.cbImportant.isChecked)
findNavController().navigate(
AddTodoFragmentDirections.actionAddTodoFragmentToTodoFragment(
binding.etAddTodo.text.toString(), binding.cbImportant.isChecked
)
)
} else {
Snackbar.make(it, "The task field can't be empty", Snackbar.LENGTH_SHORT).show()
}
}
}
}
This is how I'm trying to get the arguments in TodoFragment.
private val args: TodoFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//setting binding and other onClickListeners but they work fine
//reading args
//this i thought would work because then args only get read if not null
args?.let { //debugger stops here and app crashes
if(args.taskname.isNotEmpty())
viewModel.onAddTodoClick(Todo(name = args.taskname, isImportant = args.isImportant))
}
/*second try which I took directly from developers.android but which doesn't make sense in my case i
think because the args could be null I guess
val todoName = args.taskname
val isImportant = args.isImportant
viewModel.onAddTodoClick(Todo(name = todoName, isImportant = isImportant))
*/
}
This is the error message i get:
I hope it is clear what I mean, otherwise, I'll update the question. It'll probably be something simple but I can't quite put my finger on it.
So credit to #Onik for the idea to leave SafeArgs away. I needed to dump the SafeArgs class call for receiving the arguments and it looks like this now. This is definitely not the cleanest way I guess but I don't know yet why the SafeArgs call doesn't work and I'm too new to Kotlin to write the following code in a cleaner way. But it works, for now.
arguments?.let {
var myArg1: String? = null
var myArg2: Boolean
arguments?.getString("argument1")?.let { arg1->
myArg1= arg1
}
arguments?.getBoolean("argument2")?.let { arg2->
myArg2= arg2
if (myArg1!= null)
//do logis with args
}
}
val args = arguments?.let {
SecondFragmentArgs.fromBundle(
it
)
}
if (args != null) {
firstDataList = args.taskName
secondDataList = args.isImportant
}
This is how the receiving fragment code should look like. This should work.
I'm attempting to pass an object between navigation fragments. I'm able to build the project, but when it launches, I get an error on the nav_graph stating: "Exception inflating nav_graph line 20". Line 20 is the argument line on the nav_graph. I just added the #Parcelize keyword to the top of the class I'm trying to pass and setup the nav_graph. Do I need to do something else?
Team Class:
#Parcelize
public class Team {
#SerializedName("idTeam")
#Expose
private String idTeam;
#SerializedName("idSoccerXML")
#Expose
private String idSoccerXML;
#SerializedName("idAPIfootball")
#Expose
private String idAPIfootball;
#SerializedName("intLoved")
#Expose
private String intLoved;
#SerializedName("strTeam")
#Expose
private String strTeam;
#SerializedName("strTeamShort")
#Expose
private String strTeamShort;
Nav_Graph:
<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/nav_graph"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="com.jaykallen.searchapi.ui.HomeFragment"
android:label="HomeFragment">
<action
android:id="#+id/action_homeFragment_to_resultsFragment"
app:destination="#id/resultsFragment" />
</fragment>
<fragment
android:id="#+id/resultsFragment"
android:name="com.jaykallen.searchapi.ui.ResultsFragment"
android:label="ResultsFragment">
<argument
android:name="choice"
app:argType="com.jaykallen.searchapi.model.Team"
app:nullable="true" />
</fragment>
</navigation>
HomeFragment Method:
private fun choiceClicked(chosen: Team) {
println("User clicked: ${chosen.strTeam}")
homeViewModel.choice = chosen
val action = HomeFragmentDirections.actionHomeFragmentToResultsFragment(chosen)
Navigation.findNavController(view!!).navigate(action)
}
ResultsFragment Method:
private fun getSafeArgs() {
arguments?.let {
val args = ResultsFragmentArgs.fromBundle(it)
teamChosen = args.choice
if (teamChosen != null) {
println("Safe Argument Received=${teamChosen?.strTeam}")
updateUi(teamChosen)
}
}
}
It turns out, all you needed to do is implement the Parcelable interface on your Java object. Normally, if you were using Kotlin, the #Parcelize annotation wouldn't have allowed you to compile without the Parcelable interface. It seems this compile time protection doesn't work for Java code.
By using Java objects, you'll also lose out on all of the automatic code generation goodies that come with the #Parcelize annotation.
In other words, I recommend you convert your Java file to Kotlin if you would like to take advantage of the #Parcelize annotation.
What I have done:
I have created Navigation Drawer Activity, As updated new format of Navigation Drawer Activity, As per new Android architecture, I got it with Navigation Component structure.
The NavigationView code with NavController and NavigationUI is below which is opening fragment when I click on any navigation item.
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_profile, R.id.nav_privacy_policy,
R.id.nav_terms, R.id.nav_contact_us, R.id.nav_share, R.id.nav_send)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
This is for nav_host_fragment:
<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:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
The navigation is happening using this navigation/mobile_navigation.xml
<?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/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.sohamerp.marsremedies.fragment.HomeFragment"
android:label="#string/menu_home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_profile"
android:name="com.sohamerp.marsremedies.fragment.ProfileFragment"
android:label="#string/menu_my_profile"
tools:layout="#layout/fragment_profile" />
<fragment
android:id="#+id/nav_privacy_policy"
android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
android:label="#string/menu_privacy_policy"
tools:layout="#layout/fragment_privacy_policy" />
<fragment
android:id="#+id/nav_terms"
android:name="com.sohamerp.marsremedies.fragment.TermsConditionFragment"
android:label="#string/menu_terms"
tools:layout="#layout/fragment_terms_condition" />
<fragment
android:id="#+id/nav_contact_us"
android:name="com.sohamerp.marsremedies.fragment.ContactUsFragment"
android:label="#string/menu_contact_us"
tools:layout="#layout/fragment_terms_condition" />
</navigation>
What I want to do:
Now I want to pass some values as a bundle (arguments) in Fragment when it's called.
Scenario: I have two fragments PrivacyPolicyFragment and TermsConditionsFragment, In both fragments, I am just opening links inside WebView accordingly. So When I click on the menu item of Privacy Policy, I will pass a link related to the same.
In this new structure navigation/mobile_navigation.xml opening fragments, How can I pass arguments?
Any help?
So I forgot to go through this link : Define Destination Arguments
But this answer helpful to all lazy peoples like me:
Add dependency in project level build.gradle:
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0"
Apply plugin in app level build.gradle:
apply plugin: "androidx.navigation.safeargs"
Using XML: predefined (static) value:
In xml file of navigation /navigation/mobile_navigation.xml declare argument tag as below or you can design through this link:
<fragment
android:id="#+id/nav_privacy_policy"
android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
android:label="#string/menu_privacy_policy"
tools:layout="#layout/fragment_privacy_policy" >
<argument
android:name="privacyPolicyLink"
app:argType="string"
android:defaultValue="http://sohamerp.com/avo/avo_privacy_policy.html"/>
</fragment>
<fragment
android:id="#+id/nav_terms"
android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
android:label="#string/menu_terms"
tools:layout="#layout/fragment_terms_condition" >
<argument
android:name="privacyPolicyLink"
app:argType="string"
android:defaultValue="http://sohamerp.com/avo/avo_privacy_policy.html"/>
</fragment>
Now you have to write code in your Fragment like:
if(getArguments() != null) {
// The getPrivacyPolicyLink() method will be created automatically.
String url = PrivacyPolicyFragmentArgs.fromBundle(getArguments()).getPrivacyPolicyLink();
}
Hope it will helps you others.
Simple and fast solution:
pass arguments between destinations
Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
and receiving
TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));
In this scenario, you can use
private NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
// Create the Bundle to pass, you can put String, Integer, or serializable object
Bundle bundle = new Bundle();
bundle.putString("link","http://yourlink.com/policy");
bundle.putSerializable("USER", user); // Serializable Object
navController.navigate(R.id.nav_terms, bundle); // called fragment with agruments
In case of any help you can reply on it
To pass arguments to other Fragments/Destinations, use Safe Args which ensures type safety. Just like #bromden illustrated, Safe Args will generate a class for each fragment/destination where an action originates. You can then pass the arguments into the action that navigates to the Fragments.
In the receiving fragment, say PrivacyFragment if your code is in Kotlin, use by navArgs() property delegate to access the arguments. i.e.
val args: PrivacyFragmentArgs by navArgs()
To better understand this, visit Pass data between destinations
In newer version of Android Studio 3.2+, below dependency and plug-in need to add in both build.gradle file
Step-1
Add dependency in Project-Level build.gradle
dependencies {
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5'
}
Apply plugins in App-Level build.gradle
plugins {
id 'androidx.navigation.safeargs'
}
Step-2
In Navigation file, res/navigation/nav_graph.xml
Declare argument tag in any fragment or inner fragment with action tag
List item
Sample xml code
<fragment
android:id="#+id/nav_register"
android:name="com.pd.demo.ui.profile.RegisterFragment"
android:label="#string/title_register"
tools:layout="#layout/fragment_register">
<action
android:id="#+id/action_nav_register_to_nav_verify_otp"
app:destination="#id/nav_verify_otp">
<argument
android:name="mobile"
app:argType="string" />
<argument
android:name="password"
app:argType="string" />
</action>
</fragment>
Step-3
Below Kotlin code, pass argument to destination fragment
val bundle = bundleOf("mobile" to binding.etMobileNo.text.toString().trim())
Navigation.findNavController(binding.root).navigate(R.id.action_nav_register_to_nav_verify_otp, bundle)
Step-4
Below Kotlin code, get bundle argument from source fragment
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mobileNo = arguments!!.getString("mobile").toString()
password = arguments!!.getString("password").toString()
}
This code will helps
You could implement NavigationView.OnNavigationItemSelectedListener
And do something like this:
override fun onNavigationItemSelected(item: MenuItem): Boolean {
drawer_layout.closeDrawers()
if (item.itemId == nv_navigation_drawer_navigation_view.checkedItem?.itemId)
return false
Handler().postDelayed({
when (item.itemId) {
R.id.nav_privacy_policy -> {
val action = FragmentDirections.actionFragmentToPrivacyFragment("Policy link")
findNavController().navigate(action)
}
}
}, DRAWER_NAVIGATION_DELAY)
return true
}
And in xml you can add argument to the recieving fragment, in this case
<fragment
android:id="#+id/nav_privacy_policy"
android:name=".fragment.PrivacyPolicyFragment"
android:label="#string/menu_privacy_policy"
tools:layout="#layout/fragment_privacy_policy">
<argument
android:name="policy"
app:argType="string" />
</fragment>
You can also pass serializable objects, enum values and arrays of primitive types.
For example:
enum class ObjectType : Serializable {
FIRST, SECOND
}
Then, add arguments to the xml
<fragment
android:id="#+id/nav_profile"
android:name="com.sohamerp.marsremedies.fragment.ProfileFragment"
android:label="#string/menu_my_profile"
tools:layout="#layout/fragment_profile" >
<argument
android:name="myObjectType"
android:defaultValue="SECOND"
app:argType="com.project.app.data.ObjectType" />
</fragment>
Note, that you should specify complete path!
Passing data from the start destination with NavController NavGraph navigate is straightforward. I use this to display order lines associated to an order header:
private void showRepositionLinesFragment(AppObjects.RepOrderHeader orderHeader) {
int number = orderHeader.getOrderNumber();
String orderNumber = String.format("%06d",number);
String createDate = orderHeader.getCreateDate();
Globals.LogTrace(this, AppAlertDialog.DialogType.Info,
"Navigate to FragRepoLines with orderNumber: " + orderNumber,false);
NavController navController = NavHostFragment.findNavController(FragmentRepositionHeaders.this);
Bundle bundle = new Bundle();
bundle.putString(getString(R.string.arg_header_ordernumber),orderNumber);
bundle.putString(getString(R.string.arg_repheader_createdate), createDate);
navController.getGraph().findNode(R.id.FragRepoLines).setLabel(orderNumber + " " + createDate);
navController.navigate(R.id.action_FragRepoHeaders_to_FragRepoLines,bundle);
}
Getting data from the fragment that handles the order lines turned to be more complicated. Tried for hours with NavController getArguments().
In the end this is what worked for me.
In the start fragment:
NavController navController = NavHostFragment.findNavController(this);
// We use a String here, but any type that can be put in a Bundle is supported
MutableLiveData<String> liveData = navController.getCurrentBackStackEntry()
.getSavedStateHandle()
.getLiveData(getString(R.string.arg_header_ordernumber));
liveData.observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(String s) {
Globals.LogTrace(this, AppAlertDialog.DialogType.Info, "+++++++++ liveData changed -> " + s, false);
}
});
In the destination fragment:
String arg = getString(R.string.arg_header_ordernumber);
NavController navController = NavHostFragment.findNavController(this);
NavBackStackEntry navBackStackEntry = navController.getCurrentBackStackEntry();
if (navBackStackEntry != null) {
SavedStateHandle savedStateHandle = navBackStackEntry.getSavedStateHandle();
if (savedStateHandle != null) {
savedStateHandle.set(arg, "000000");
} else {
Globals.LogTrace(this, AppAlertDialog.DialogType.Info,"savedStateHandle == null",false);
}
} else {
Globals.LogTrace(this, AppAlertDialog.DialogType.Info,"navBackStackEntry == null",false);
}
Source: Interact programmatically with the Navigation component
I changed the navController.getPreviousBackStackEntry() for navController.getCurrentBackStackEntry()
I had the same issue but I´m still not able to pass the arguments using fragment directions. Since I need the value in several of my fragments I decided to use a companion object in my main activity. It´s probably not the best but it solves the problem:
class MainActivity : AppCompatActivity() {
companion object{
var myGlobalVar = "Example"
}
override fun onCreate(savedInstanceState: Bundle?) {....
Then I can access its value in all of my fragments by importing it:
import myAppPackage.MainActivity.Companion.myGlobalVar
I had to delete the argument from my navGraph but i can still access it in the background.
it looks like it isn't possible to process a deeplink with query parameters in the new Jetpack Navigation library. If you put the following to the navigation.xml:
<deepLink app:uri="scheme://host/path?query1={query_value}" /> then the deeplink does not open the fragment.
After some digging I found that the culprit is probably in the NavDeepLink when it transforms the url from xml to a Pattern regex. Looks like the problem is a question mark that is not excaped.
I wrote a test which fails:
#Test
fun test() {
val navDeepLink = NavDeepLink("scheme://host/path?query1={query_value}")
val deepLink = Uri.parse("scheme://host/path?query1=foo_bar")
assertEquals(true, navDeepLink.matches(deepLink))
}
To make the test pass all I have to do is to escape the ? as following:
#Test
fun test() {
val navDeepLink = NavDeepLink("scheme://host/path\\?query1={query_value}")
val deepLink = Uri.parse("scheme://host/path?query1=foo_bar")
assertEquals(true, navDeepLink.matches(deepLink))
}
Am I missing something really basic here to pass query values to my Fragment or is this not supported feature at the moment?
You need to add DeepLink Navigation to AndroidManifest.xml ( special Activity that handles the fragment) so when deeplink clicked your app can receive the DeepLink and pass it to that navigation and fragment & can read it as argument:
I'll put Kotlin codes here :
In your navigation file, your fragment that gonna handle the deeplink with arguements must be like this:
<fragment
android:id="#+id/menu"
android:name="ir.hamplus.fragments.MainFragment"
android:label="MainFragment">
<action android:id="#+id/action_menu_to_frg_messenger_main"
app:destination="#id/frg_messenger_main"/>
<deepLink app:uri="http://hamplus.ir/request/?key={key}&id={id}" />
<argument android:name="key" app:argType="string"/>
<argument android:name="id" app:argType="string"/>
</fragment>
read deeplink arguments in frasgment /Activity :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Or in activity read the intent?.data
arguments?.let {
Log.i("TAG", "Argument=$arguments")
var key = it.getString("key")
Log.i("TAG", "key=$key")
var id = it.getString("id")
Log.i("TAG", "id=$id")
}
}
Also add the nav-graph on AndroidManifest.xml in related Activity :
<activity
android:name=".MainActivity"
android:theme="#style/AppTheme.NoActionBar" >
<nav-graph android:value="#navigation/main_navigation"/>
</activity>
package androidx.navigation
import android.net.Uri
import androidx.test.runner.AndroidJUnit4
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
#RunWith(AndroidJUnit4::class)
class NavTest {
#Test
fun test() {
val navDeepLink = NavDeepLink("scheme://host/path\\?query1={query_value1}&query2={query_value2}")
val deepLink = Uri.parse("scheme://host/path?query1=foo_bar&query2=baz")
val bundle = navDeepLink.getMatchingArguments(deepLink)!!
assertTrue(bundle.get("query_value1") == "foo_bar")
assertTrue(bundle.get("query_value2") == "baz")
}
}
In the end it looks like NavDeepLink treats non escaped as "?" match-zero-or-one quantifier. You need to escape it. In other words, we have a leak of non documented implementation detail.
It might be not related to the exactly this case, but there is some similar issues with escaping "&" with "\" when using add command.
The issue was also touched in the following channel.
I am rewriting my simple UI app to use Navigation architecture component, I need to pass a Pojo that implements Parcelable, have not seen any doc on how to do that.
Any help would be appreciated.
Since safe-args-gradle-plugin:1.0.0-alpha03 you can use Parcelable objects by using their fully qualified class name:
<argument
android:name="item"
app:argType="com.example.app.model.Item"/>
Parcelable arguments are now supported, using a fully qualified class name for app:type. The only default value supported is "#null" (https://issuetracker.google.com/issues/79563966)
Source: https://developer.android.com/jetpack/docs/release-notes
To support nullability one has to use android:defaultValue="#null" with app:nullable="true".
I know the answer is already there but this may help someone. Code snippet
In build.gradle add this dependancy
ext{
...
navigation_version = '1.0.0-alpha11'
}
dependencies {
...
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
}
In app/build.gradle
apply plugin: 'androidx.navigation.safeargs'
...
In Navigation graph
<fragment
android:id="#+id/source_fragment_id"
android:name="app.test.SourceFragment"
android:label="#string/source_fragment_label"
tools:layout="#layout/source_fragment_layout">
<action
android:id="#+id/action_source_fragment_to_destination_fragment"
app:destination="#id/destination_fragment_id"
...
/>
</fragment>
<fragment
android:id="#+id/destination_fragment_id"
android:name="app.test.DestinationFragment"
android:label="#string/destination_fragment_label"
tools:layout="#layout/destination_fragment_layout">
<argument
android:name="variableName"
app:argType="app.test.data.model.CustomModel" />
...
</fragment>
Note: CustomModel should be Parcelable or Serializable.
When navigating to this DestinationFragment from SourceFragment
val direction = SourceFragmentDirections.ActionSourceFragmentToDestinationFragment(customModel)
findNavController().navigate(direction)
Now retrieving the value from bundle in DestinationFragment
...
import app.test.DestinationFragmentArgs.fromBundle
class DestinationFragment : Fragment() {
val variableName by lazy {
fromBundle(arguments!!).variableName
}
...
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Log.e(DESTINATION_FRAGMENT_TAG,"onCreateView")
//Can use CustomModel variable here i.e. variableName
}
}
Right now you can't use safe args with types apart from integer, string, inferred and reference, there's an issue opened asking for other types.
What you can do now is to normally pass a bundle when using the navigate() method to navigate to a destination:
var bundle = bundleOf("amount" to amount)
view.findNavController().navigate(R.id.confirmationAction, bundle)
And you can use the usual getArguments (or just arguments in kotlin) to retrieve that:
val tv = view.findViewById(R.id.textViewAmount)
tv.text = arguments.getString("amount")
You can use boolean, reference, integer, long, string, enum, parcelable and even serializable. But forget about the last one ;-)
Better use the latest plugin version safe-args-gradle-plugin:1.0.0-alpha08 and specify the fully qualified classname:
<fragment
...>
<argument
android:name="data"
app:argType="com.example.ParcelableData" />
</fragment>
from your
package com.example
data class ParcelableData(val content: String) : Parcelable { ... }
And you can send arrays of all the argTypes:
<argument
android:name="data"
app:argType="string[]" />