Solution 1 :
The code B should still be working fine .
I made a look into findNavController()
. This is an extension function for simpifying the code , the code for extension function is
fun Activity.findNavController(@IdRes viewId: Int): NavController =
Navigation.findNavController(this, viewId)
Now looking in to the code of findNavController()
inside Navigation
we see below
@NonNull
public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
View view = ActivityCompat.requireViewById(activity, viewId);
NavController navController = findViewNavController(view);
if (navController == null) {
throw new IllegalStateException("Activity " + activity
+ " does not have a NavController set on " + viewId);
}
return navController;
}
The viewId we are passing in argument is used in the first line
View view = ActivityCompat.requireViewById(activity, viewId);
now looking into requireViewById()
inside ActivityCompat
we see
@NonNull
public static <T extends View> T requireViewById(@NonNull Activity activity, @IdRes int id) {
if (Build.VERSION.SDK_INT >= 28) {
return activity.requireViewById(id);
}
T view = activity.findViewById(id);
if (view == null) {
throw new IllegalArgumentException("ID does not reference a View inside this Activity");
}
return view;
}
for api 28 and plus the method which gets called is
@NonNull
public final <T extends View> T requireViewById(@IdRes int id) {
T view = findViewById(id);
if (view == null) {
throw new IllegalArgumentException("ID does not reference a View inside this Activity");
}
return view;
}
So as long as the view (inside which the nav_host_fragment
is present) is attached to activity the code which you wrote for finding the nav controller should work completely fine .
class TasksActivity : AppCompatActivity() {
private lateinit var binding: TasksActBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = TasksActBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view) //you are attaching view to activity here , make sure you always call this before the next line , else you will get IllegalStateException
val navController: NavController = findNavController(R.id.nav_host_fragment)
}
}
I have not tested the code personally but from what I see it should work perfectly fine.
Solution 2 :
We are using ViewBinding to get a reference of view itself. If you are using viewbinding in TextView, you will get a reference of the View.
In the case of NavCotroller, If you use Viewbinding, you will get a reference to a fragment, while findNavController expect ViewId of type integer.
findNavController(@IdRes viewId: int)
Solution 3 :
The correct working way is as follows:
FragmentContainerView has to be accessed from the supportFragmentManager:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
val navController = navHostFragment.navController
Problem :
Normally, I use val navController: NavController = findNavController(R.id.nav_host_fragment)
in Code A to find NavController, it’s based R.id.nav_host_fragment
.
Now I use view binding in the app just like Code B, how can I NavController if I use view binding ?
BTW, in my mind R.id.nav_host_fragment
will not be available in view binding , right?
Code A
class TasksActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.tasks_act)
val navController: NavController = findNavController(R.id.nav_host_fragment)
}
}
Code B
class TasksActivity : AppCompatActivity() {
private lateinit var binding: TasksActBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = TasksActBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//val navController: NavController = findNavController(R.id.nav_host_fragment)
}
}
tasks_act.xml
<androidx.drawerlayout.widget.DrawerLayout
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/drawer_layout"
android_layout_width="match_parent"
android_layout_height="match_parent"
tools_context=".tasks.TasksActivity"
tools_openDrawer="start">
<LinearLayout
android_layout_width="match_parent"
android_layout_height="match_parent"
android_orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android_layout_width="match_parent"
android_layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android_id="@+id/toolbar"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_minHeight="?attr/actionBarSize"
android_theme="@style/Toolbar"
app_popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>
<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_navGraph="@navigation/nav_graph" />
</LinearLayout>
..
</androidx.drawerlayout.widget.DrawerLayout>
Comments
Comment posted by HelloCW
Thanks! but
Comment posted by stackoverflow.com/questions/60733289/…
I’m not sure, but you can check this answer:
Comment posted by Stachu
viewId