I'm providing data transfer between fragments in two different ways, first is working normal, while a safe data type cause run-time crash. I'm using that Android docs: https://developer.android.com/topic/libraries/architecture/navigation/navigation-implementing#Safe-args
Don't understand how could I resolve the problem. Thanks for your help
07-13 11:40:07.986 8119-8119/com.flexdecision.ak_lex.navigationsimple E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.flexdecision.ak_lex.navigationsimple, PID: 8119
java.lang.IllegalArgumentException: navigation destination com.flexdecision.ak_lex.navigationsimple:id/transferAction is unknown to this NavController
at androidx.navigation.NavController.navigate(NavController.java:669)
at androidx.navigation.NavController.navigate(NavController.java:628)
at androidx.navigation.NavController.navigate(NavController.java:690)
at com.flexdecision.ak_lex.navigationsimple.InitialFragment.makeTransfer(InitialFragment.java:58)
at com.flexdecision.ak_lex.navigationsimple.InitialFragment.lambda$onViewCreated$0(InitialFragment.java:47)
at com.flexdecision.ak_lex.navigationsimple.-$$Lambda$InitialFragment$shEoLbIe0sVhbTcJ2Al_FvBuU7g.onClick(lambda)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Navigation graph:
<?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/nav_graph"
app:startDestination="@id/initialFragment">
<fragment
android:id="@+id/initialFragment"
android:name="com.flexdecision.ak_lex.navigationsimple.InitialFragment"
android:label="fragment_initial"
tools:layout="@layout/fragment_initial">
<action
android:id="@+id/transferAction"
app:destination="@+id/nextFragment" />
</fragment>
<fragment
android:id="@+id/nextFragment"
android:name="com.flexdecision.ak_lex.navigationsimple.NextFragment"
android:label="fragment_next"
tools:layout="@layout/fragment_next" >
<argument
android:name="firstName"
android:defaultValue="none"
app:type="string" />
<argument
android:name="lastName"
android:defaultValue="none"
app:type="string" />
</fragment>
</navigation>
Activity layout:
<android.support.constraint.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">
<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_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</android.support.constraint.ConstraintLayout>
Sender:
import androidx.navigation.Navigation;
public class InitialFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_initial, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button transactionBtn = view.findViewById(R.id.transaction);
transactionBtn.setOnClickListener(v -> makeTransfer(v));
}
private void makeTransfer(View view) {
Bundle bundle = new Bundle();
bundle.putString("name", "Aleksey");
Navigation.findNavController(view).navigate(R.id.transferAction, bundle);
//Type safe passing data
InitialFragmentDirections.TransferAction action = InitialFragmentDirections.transferAction();
action.setLastName("Petrov");
Navigation.findNavController(view).navigate(action);
}
}
Receiver:
public class NextFragment extends Fragment {
private static final String ARG_PARAM1 = "name";
private String mParam1;
private TextView firstName;
public NextFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
Log.d("Next", "Param: " + mParam1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_next, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
firstName = view.findViewById(R.id.firstName);
TextView lastName = view.findViewById(R.id.lastNameTV);
firstName.setText(mParam1);
String ln = NextFragmentArgs.fromBundle(getArguments()).getLastName();
lastName.setText(ln);
}
}
additional:
You calling twice to 'Navigation.findNavController(view).navigate':
private void makeTransfer(View view) {
Bundle bundle = new Bundle();
bundle.putString("name", "Aleksey");
Navigation.findNavController(view).navigate(R.id.transferAction, bundle);
//Type safe passing data
InitialFragmentDirections.TransferAction action = InitialFragmentDirections.transferAction();
action.setLastName("Petrov");
Navigation.findNavController(view).navigate(action);
}
First time with bundle and second time with safe args, but after the first call your destination already changed to 'nextFragment', and when you call second 'navigate' the 'NavController' looking for 'transferAction' action inside 'nextFragment' and throws exception.