I am implementing navigation between Fragments from different flows (single-activity architecture with flow fragments) meaning from one nested graph to another. I am trying to pass one testID argument using Safe Args. In my origins Fragment I use generated class to create action to further set parameter:
LevelFlowFragmentDirections.ActionGlobalTestFlowFragment action = LevelFlowFragmentDirections.actionGlobalTestFlowFragment();
action.setTestID(1);
However, when I run the project it shows this error:
Here is what my project structure looks like:
LevelFlowFragment.java code:
package kz.rating.onaikazakh.presentation.ui.fragments.levelflow;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import kz.rating.onaikazakh.NavGraphDirections;
import kz.rating.onaikazakh.R;
import kz.rating.onaikazakh.presentation.ui.recyclerviews.section.SectionAdapter;
import kz.rating.onaikazakh.presentation.ui.utils.NavUtils;
public class LevelFlowFragment extends Fragment implements View.OnClickListener{
private NavController navController;
LevelsViewModel vm;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*vm = new ViewModelProvider(this).get(LevelsViewModel.class);
vm.data.observe(this, data -> {
if (data!=null) adapter = new SectionAdapter(this, data);
});*/
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.flow_fragment_level, container, false);
RecyclerView levelsRecView = rootView.findViewById(R.id.recyclerView_test_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
levelsRecView.setLayoutManager(layoutManager);
int scrollposition = ((LinearLayoutManager) levelsRecView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
levelsRecView.scrollToPosition(scrollposition);
SectionAdapter adapter = new SectionAdapter(this, new String[]{"level 1", "level 2", "level 3"});
levelsRecView.setAdapter(adapter);
return rootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
navController = Navigation.findNavController(view);
Button button_skip = getView().findViewById(R.id.button_test_skip);
button_skip.setOnClickListener(this);
}
@Override
public void onClick(View v) {
NavUtils.navigate(R.id.action_global_mainFlowFragment, this);
}
public void onViewHolderClickListener(String level){
Bundle bundle = new Bundle();
LevelFlowFragmentDirections.ActionGlobalTestFlowFragment action = LevelFlowFragmentDirections.actionGlobalTestFlowFragment();
NavDirections directions = LevelFlowFragmentDirections.actionGlobalTestFlowFragment();
//temporary implementation
switch(level){
case "level 1":
action.setTestID(1);
bundle.putInt("testID", 1);
break;
case "level 2":
action.setTestID(2);
bundle.putInt("testID", 2);
break;
case "level 3":
action.setTestID(3);
bundle.putInt("testID", 3);
break;
}
NavUtils.navigate(R.id.action_global_testFlowFragment, this, bundle);
}
}
Main graph nav_graph.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/nav_graph"
tools:ignore="InvalidNavigation"
app:startDestination="@id/langFlowFragment">
<action
android:id="@+id/action_global_signFlowFragment"
app:destination="@id/signFlowFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_mainFlowFragment"
app:destination="@id/mainFlowFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_levelFlowFragment"
app:destination="@id/levelFlowFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_langFlowFragment"
app:destination="@id/langFlowFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_testFlowFragment"
app:destination="@id/testFlowFragment"
app:popUpTo="@id/nav_graph">
<argument
android:name="testID"
app:argType="integer"
android:defaultValue="0" />
</action>
<fragment
android:id="@+id/mainFlowFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.mainflow.MainFlowFragment"
android:label="flow_fragment_main"
tools:layout="@layout/flow_fragment_main" />
<fragment
android:id="@+id/signFlowFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.signflow.SignFlowFragment"
android:label="flow_fragment_sign"
tools:layout="@layout/flow_fragment_sign" />
<fragment
android:id="@+id/levelFlowFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.levelflow.LevelFlowFragment"
android:label="flow_fragment_level"
tools:layout="@layout/flow_fragment_level" />
<fragment
android:id="@+id/langFlowFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.langflow.LanguageFlowFragment"
android:label="flow_fragment_lang"
tools:layout="@layout/flow_fragment_lang" />
<fragment
android:id="@+id/testFlowFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.testflow.TestFlowFragment"
android:label="flow_fragment_test"
tools:layout="@layout/flow_fragment_test" >
<argument
android:name="testID"
app:argType="integer"
android:defaultValue="0" />
</fragment>
</navigation>
test_graph.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/test_graph"
app:startDestination="@id/questionFragment">
<fragment
android:id="@+id/questionFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.testflow.question.QuestionFragment"
android:label="fragment_question"
tools:layout="@layout/fragment_test_question">
<action
android:id="@+id/action_questionFragment_to_answerFragment"
app:destination="@id/answerFragment" />
<argument
android:name="testID"
app:argType="integer"
android:defaultValue="0" />
</fragment>
<fragment
android:id="@+id/answerFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.testflow.answer.AnswerFragment"
android:label="fragment_answer"
tools:layout="@layout/fragment_test_answer">
<action
android:id="@+id/action_answerFragment_to_questionFragment"
app:destination="@id/questionFragment" />
<action
android:id="@+id/action_answerFragment_to_completedFragment"
app:destination="@id/completedFragment" />
</fragment>
<fragment
android:id="@+id/completedFragment"
android:name="kz.rating.onaikazakh.presentation.ui.fragments.testflow.completion.CompletionFragment"
android:label="fragment_completed"
tools:layout="@layout/fragment_test_complete">
<action
android:id="@+id/action_completedFragment_to_questionFragment"
app:destination="@id/questionFragment" />
</fragment>
</navigation>
flow_fragment_test.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:fitsSystemWindows="true">
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/wave_imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/wave" />
</RelativeLayout>
<FrameLayout
android:id="@+id/container_test"
android:layout_width="0dp"
android:layout_height="0dp"
android:fitsSystemWindows="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_top_margin"
android:layout_marginBottom="@dimen/activity_bottom_margin">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_test"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/test_graph" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
build.gradle :app:
apply plugin: 'com.android.application'
apply plugin: 'androidx.navigation.safeargs'
android {
compileSdkVersion 33
buildToolsVersion "30.0.2"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
checkReleaseBuilds false
}
defaultConfig {
applicationId "kz.rating.onaikazakh"
minSdkVersion 24
targetSdkVersion 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures {
viewBinding = true
}
sourceSets {
main {
java {
srcDirs += 'build/generated/source/navigation-args'
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
def nav_version = "2.5.3"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:$nav_version"
implementation project(path: ':domain')
implementation project(path: ':data')
}
build.gradle :project:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
def nav_version = "2.5.3"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
What I have tried:
- Clean, Rebuild
- I saw Safeargs library doesnt generate direction class, and added
sourceSets {
main {
java {
srcDirs += 'build/generated/source/navigation-args'
}
}
}
- Updated all dependencies and plugins
- I also saw Build error: Cannot find symbol. Points to navigation actions, but the author deleted nested graph which worked. In my case I cannot apply this solution.
- Saw Action is not generated in FragmentDirections when Fragment is used in a second nav graph, but I already have @+id in the action and in every graph.
6) Off-topic: later I tried another way of passing data via creating Bundle and retrieving it in both QuestionFragment and TestFlowFragment. Neither it produced errors nor passed any data. This is code from destination fragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vm = new ViewModelProvider(this).get(TestSharedViewModel.class);
int id = getArguments().getInt("testID");
Log.v("AAA", "id is " + id);
vm.setID(id);
}
I would appreciate any help on resolving the problem or other ways to implement passing data between those fragments.
Edit
What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?
Does not resolve my issue. Most of them are about wrong import, dependencies or misspelling, but these are generated classes, LevelFlowFragmentDirections.ActionGlobalTestFlowFragment was offered by IDE; when I tried to remove the LevelFlowFragmentDirections to follow official android guide it offered referencing LevelFlowFragmentDirections.ActionGlobalTestFlowFragment from different modules(?) and I tried both app and app.main.
In regard to JDK and Gradle compatability, it used to be 1.8 with gradle 4.0.1, I upgraded to 11 and 7.0.2.

