Search code examples
androidandroid-jetpackandroid-safe-args

How to navigate using SafeArgs


I just started to use the Jetpack Navigation components and SafeArgs for navigation in Android. However, I do not understand how I can navigate from one destination to another one (I read the google documentation but this was confusing for me). So I have a Menu_Fragment class that has a link in the NavGraph to a Softdrink class. A Menu_FragmentDirections class was automatically created. However, I do not know how to use it within the Menu_Fragment class to implement an OnClick listener event. Here I have the onClick method in the Menu_Fragment class (see https://developer.android.com/guide/navigation/navigation-navigate):

@Override
public void onClick(View view) {

    if(view.getId() == R.id.imageButton_Softdrinks_en) {
        float amount = ...;
        action =
                Menu_FragmentDirections
                        .actionMenuFragmentToSoftdrinks(amount);
        Navigation.findNavController(view).navigate(action);

    }

}

Here you can see the Menu_FragmentDirections class:

package com.example.td.barapp;

import androidx.annotation.NonNull;
import androidx.navigation.ActionOnlyNavDirections;
import androidx.navigation.NavDirections;

public class Menu_FragmentDirections {
  private Menu_FragmentDirections() {
  }

  @NonNull
  public static NavDirections actionMenuFragmentToSoftdrinks() {
    return new ActionOnlyNavDirections(R.id.action_menu_Fragment_to_softdrinks);
  }
}

And here you can see the NavGraph:

<?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/menu_Fragment">

    <fragment
        android:id="@+id/menu_Fragment"
        android:name="com.example.td.barapp.Menu_Fragment"
        android:label="fragment_menu_"
        tools:layout="@layout/fragment_menu" >
        <action
            android:id="@+id/action_menu_Fragment_to_softdrinks"
            app:destination="@id/softdrinks" />
    </fragment>
    <fragment
        android:id="@+id/softdrinks"
        android:name="com.example.td.barapp.Softdrinks"
        android:label="fragment_softdrinks"
        tools:layout="@layout/fragment_softdrinks" />
</navigation>

Can anybody tell me, what I have to do in the onCreateMethod() posted above.I get the error messages: "Cannot resolve symbol 'action'" and "Cannot resolve symbol 'Navigation'" (and of course the error for using the unexpected token '...')

I'd appreciate every comment and would be quite thankful for your help.

Update here is the complete Menu_Fragment class with the onCreateMethod:

package com.example.td.barapp;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.example.td.barapp.databinding.FragmentMenuBinding;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link Menu_Fragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class Menu_Fragment extends Fragment implements View.OnClickListener {

    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;



    private Menu_Fragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment Menu_Fragment.
     */
    // TODO: Rename and change types and number of parameters
    public static Menu_Fragment newInstance(String param1, String param2) {
        Menu_Fragment fragment = new Menu_Fragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }


    }

    private FragmentMenuBinding binding;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = FragmentMenuBinding.inflate(inflater, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        binding.imageButtonCocktailsEn.setOnClickListener(this);
        binding.imageButtonCocktailsAlcfreeEn.setOnClickListener(this);
        binding.imageButtonLongdrinksEn.setOnClickListener(this);
        binding.imageButtonWhiskyEn.setOnClickListener(this);
        binding.imageButtonLiquorEn.setOnClickListener(this);
        binding.imageButtonBeerEn.setOnClickListener(this);
        binding.imageButtonSoftdrinksEn.setOnClickListener(this);
        binding.imageButtonHotDrinksEn.setOnClickListener(this);

    }

    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }


    @Override
    public void onClick(View view) {

        if(view.getId() == R.id.imageButton_Softdrinks_en) {
            float amount = 0f;
            Menu_FragmentDirections.ActionMenuFragmentToSoftdrinks  action = Menu_FragmentDirections
                    .actionMenuFragmentToSoftdrinks(amount);

        }

    }
}

Solution

  • You are missing the object type before the action.

    It would like like this:

    Menu_FragmentDirections.ActionMenuFragmentToSoftdrinks action = Menu_FragmentDirections
                        .actionMenuFragmentToSoftdrinks(amount);
    

    And the error:

    error: illegal start of expression float amount = ...;

    It's because you want a float and you are passing "...". It must be a floating number.

    Ie:float amount = 0.6f or float amount = 0f.

    EDIT:

    To add an argument to a fragment, please do the following steps:

    Select the destination fragment and click on the plus as highlighted. enter image description here

    After that, choose the type of variable you want and give it a name enter image description here

    Rebuild your project and check it if it's now working.

    Hope it helped.