Reputation: 661
I tried to access NavController
from the home fragment but had no success. Spent the whole day but still had no success at all. The app crashes in HomeFragment
in this line of code:
navController = requireActivity().findNavController(R.id.nav_host_fragment)
Here is the code that I have implemented:
HomeFragmnet
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var navController: NavController
private var itemList: MutableList<Home?> = ArrayList()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
navController = requireActivity().findNavController(R.id.nav_host_fragment)
homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
recyclerView = root.findViewById(R.id.homeRecyclerView)
return root
}
}
This is xml implementation of nav_bar.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"
app:startDestination="@id/nav_home">
<fragment
android:id="@+id/nav_home"
android:name="fi.gambitlabs.pworker.ui.home.HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_home" />
</navigation>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
content_main.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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_main">
<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_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var navController: NavController
private lateinit var navView: NavigationView
override fun onCreate(savedInstanceState: Bundle?) {
// Disable dark mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
navView = findViewById(R.id.nav_view)
navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
Error Logs
E/AndroidRuntime: FATAL EXCEPTION: main
Process: fi.gambitlabs.pworker, PID: 12300
java.lang.RuntimeException: Unable to start activity ComponentInfo{fi.gambitlabs.pworker/fi.gambitlabs.pworker.MainActivity}: android.view.InflateException: Binary XML file line #14 in fi.gambitlabs.pworker:layout/activity_main: Binary XML file line #19 in fi.gambitlabs.pworker:layout/content_main: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.view.InflateException: Binary XML file line #14 in fi.gambitlabs.pworker:layout/activity_main: Binary XML file line #19 in fi.gambitlabs.pworker:layout/content_main: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #19 in fi.gambitlabs.pworker:layout/content_main: Error inflating class fragment
Caused by: java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
at android.app.Activity.requireViewById(Activity.java:3375)
at androidx.core.app.ActivityCompat.requireViewById(ActivityCompat.java:366)
at androidx.navigation.Navigation.findNavController(Navigation.java:58)
at *emphasized text*androidx.navigation.ActivityKt.findNavController(Activity.kt:30)
at fi.gambitlabs.pworker.ui.home.HomeFragment.onCreateView(HomeFragment.kt:30)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:392)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:140)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1261)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1117)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
E/AndroidRuntime: at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1261)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1117)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:699)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:195)
at fi.gambitlabs.Pworker.MainActivity.onCreate(MainActivity.kt:28)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.PWorker.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/Theme.PWorker.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Dependencies
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment:2.3.5'
implementation 'androidx.navigation:navigation-ui:2.3.5'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//Firebase
implementation platform('com.google.firebase:firebase-bom:28.2.0')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-crashlytics-ktx'
}
Have spent lots of time trying to find a solution on google but nothing works and now I am stuck. It crashes when trying to access requireActivity().findNavController(R.id.nav_host_fragment) in HomeFragment but no crashes with the same code in MainActivity as seen on code snippet.
Any help is highly appreciable.
Upvotes: 1
Views: 2774
Reputation: 40888
I tried to access NavController from the home fragment but had no success.
You can't access the NavController
because you try to access it before the setContentView()
of the activity get finished; i.e you are trying to access a resource R.id.nav_host_fragment
that doesn't exist yet.
And the reason because the HomeFragment
is initially hosted by the activity, and it's a part of the activity layout; and in order to draw the fragment on the activity, it needs to take a chance first to get the fragment layout before returning the entire layout with setContentView()
To verify that add the below log messages in the activity (MainActivity
) & HomeFragment
:
Activity:
class MainActivity : AppCompatActivity() {
// .... Code omitted
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "MainActivity onCreate: BEFORE setContentView()")
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Log.d(TAG, "MainActivity onCreate: AFTER setContentView()")
// .... Code omitted
Log.d(TAG, "MainActivity onCreate: END")
}
Fragment:
class HomeFragment : Fragment() {
// .... Code omitted
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
Log.d(TAG, "HomeFragment onCreateView: START")
homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
// .... Code omitted
Log.d(TAG, "HomeFragment onCreateView: END")
return root
}
The outcome:
D/LOG_TAG: MainActivity onCreate: BEFORE setContentView()
D/LOG_TAG: HomeFragment onCreateView: START
D/LOG_TAG: HomeFragment onCreateView: END
D/LOG_TAG: MainActivity onCreate: AFTER setContentView()
D/LOG_TAG: MainActivity onCreate: END
How to solve this:
You can set the navController
in lifecycle methods beyond onCreateView()
& onViewCreated()
of the HomeFragment
like in onStart()
, or onResume()
class HomeFragment : Fragment() {
// .... Code omitted
override fun onStart() {
super.onStart()
val navController = requireActivity().findNavController(R.id.nav_host_fragment)
}
Upvotes: 2
Reputation: 36
Seems like you haven't included content_main.xml in your activity_main.xml
Upvotes: 0