Reputation: 31
I have implemented an argument to be passed between fragments in nav_graph, however when I attempt to set the argument in the originating fragment, the argument is not found by the NavDirections.
Note that Navigation works fine before trying to pass the argument.
If I do a Clean Project I lose the NavDirections. If I do a Rebuild I lose the argument.
Gradle:app
//Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
apply plugin: "androidx.navigation.safeargs.kotlin"
nav_graph.xml
<fragment
android:id="@+id/destination_home"
android:name="com.android.joncb.flightlogbook.HomeFragment"
android:label="@string/lblHome"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_home_to_fltHistory"
app:destination="@id/destination_fltHistory" />
<action
android:id="@+id/action_home_to_stats"
app:destination="@id/destination_statistics" />
<action
android:id="@+id/action_home_to_newFlight"
app:destination="@id/destination_newFlight" />
<action
android:id="@+id/action_home_to_fltDetails"
app:destination="@id/destination_fltDetails" />
<argument
android:name="fltData"
app:argType="string" />
</fragment>
and in my Home Fragment I get the error "Unresolved reference: fltData"
card_nextFlight.setOnClickListener {
val actionDetails = HomeFragmentDirections.actionHomeToFltDetails()
actionDetails.fltData ( flightData.toString())
Navigation.findNavController(it).navigate(actionDetails)
}
flightData is a data class
data class FlightDTO(
var airlineName: String, var faCode: String, var fltNo: String, var aircraft: String,
var depAP: String, var arrAP: String, var schedDep: String, var schedArr: String,
var date: String, var leg: Int = 0, var actDep: String = "", var actArr: String = "" ){
...
override fun toString(): String {
return "$airlineName $faCode $fltNo $aircraft $depAP $schedDep $arrAP $schedDep $date"
}
}
I want to pass the class ideally by making the class Parcelable, but until I can pass a string, there is no point venturing down the parcel line.
Upvotes: 3
Views: 6578
Reputation: 6938
For my case, I wrote a buggy code like that -
NavController navController = NavHostFragment.findNavController(this);
NavDirections navDirections = MyDestinationFragmentDirections.actionMyAction(myArgumentValue);
navController.navigate(navDirections.getActionId());
Then I change the last line into this -
navController.navigate(navDirections);
And finally,it worked as expected!!!
The logic behind this was, in NavController
class the method which accepting int (resId
of action) always put null argument -
public void navigate(@IdRes int resId) {
navigate(resId, null);
}
So we should use -
public void navigate(@NonNull NavDirections directions) {
navigate(directions.getActionId(), directions.getArguments());
}
method if we are willing to pass an arguments via an action.
Upvotes: 1
Reputation: 365
my mistake was the following. I had something like
NavDirections action =
SpecifyAmountFragmentDirections
.actionSpecifyAmountFragmentToConfirmationFragment();
I changed to something like
ConfirmationAction action =
SpecifyAmountFragmentDirections
.actionSpecifyAmountFragmentToConfirmationFragment();
Upvotes: 0
Reputation: 31
Rather than pass a data class, I have created a JSON String and passed a string
card_nextFlight.setOnClickListener {
val dataString = flightData.toJSONString()
val actionDetails = HomeFragmentDirections.actionHomeToFltDetails(dataString)
Navigation.findNavController(it).navigate(actionDetails)
}
To get this to work I had to modify the actionHomeToFltDetails function to receive a string in HomeFragmentsDirections
fun actionHomeToFltDetails(fltData: String): NavDirections = ActionHomeToFltDetails(fltData)
}
I could not get @Lucho approach to handle the arg in the destination fragment to work so reverted to bundle management, and converted the JSON string back to a data class
const val ARG_PARAM1 = "fltData"
.
.
.
arguments?.let {
argFltData = it.getString(ARG_PARAM1)
Log.e("args","Passed Argument: $argFltData")
fltData = gson.fromJson(argFltData, FlightDTO::class.java)
}
Thanks again for your input and I hope this helps someone else through the drama.
Upvotes: -2
Reputation: 1547
You are writing your XML wrong, think like this : The way I structure my XML properties is the way the generated code will look like and received between destinations sort of...
So basically in your nav_graph.xml you should change to:
<fragment
android:id="@+id/destination_home"
android:name="com.android.joncb.flightlogbook.HomeFragment"
android:label="@string/lblHome"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_home_to_fltHistory"
app:destination="@id/destination_fltHistory" />
<action
android:id="@+id/action_home_to_stats"
app:destination="@id/destination_statistics" />
<action
android:id="@+id/action_home_to_newFlight"
app:destination="@id/destination_newFlight" />
<action
android:id="@+id/action_home_to_fltDetails"
app:destination="@id/destination_fltDetails">
<argument
android:name="fltData"
app:argType="string" />
</action>
</fragment>
and in your destination it should look something like:
<fragment
android:id="@+id/destination_fltDetails"
android:name="com.android.joncb.flightlogbook.FlightDetailsFragment"
android:label="@string/lblFlightDetails"
tools:layout="@layout/fragment_flight_details">
<argument
android:name="fltData"
app:argType="string" />
</fragment>
and in your flight details fragment the properties are received by using:
private val args: FlightDetailsFragmentArgs by navArgs()
println(args.fltData) // prints the navigation data
UPDATE:
Forgot to mention your OnClickListener in your Home fragment that would look more like this:
card_nextFlight.setOnClickListener {
val actionDetails = HomeFragmentDirections.actionHomeToFltDetails(flightData.toString())
Navigation.findNavController(it).navigate(actionDetails)
}
Upvotes: 6