Issue
I'm having an issue with a very simple task with Navigation component. I have just 2 screens: MainFragment and SearchFragment.
When I try to go from MainFragment to SearchFragment by navigation with an action it works perfectly. Then I press the back button and naturally it goes back to the MainFragment.
The issue is, when I click the same button the second time to go again to the SearchFragment, I receive the following error:
java.lang.IllegalArgumentException: Navigation action/destination action_mainFragment_to_searchFragment cannot be found from the current destination Destination(searchFragment)
I'm navigating from the MainFragment to Search like this:
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
I tried redoing the nav_graph.xml but without success.
If I just navigate with the id directly, it works fine and I go back and forth as many times as I want
findNavController().navigate(R.id.searchFragment)
Any ideas how to fix the issue with the safe args?
Edit:
This is my nav_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_main"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="news.presentation.main.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main">
<action
android:id="@+id/action_mainFragment_to_searchFragment"
app:destination="@id/searchFragment" />
</fragment>
<fragment
android:id="@+id/searchFragment"
android:name="news.presentation.search.SearchFragment"
android:label="fragment_search"
tools:layout="@layout/fragment_search" />
</navigation>
This is the activity (it's basically just a container for the fragments):
This is the activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView 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/homeFragContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_main"
tools:context=".presentation.HomeActivity" />
And this is the HomeActivity.kt
@AndroidEntryPoint
class HomeActivity : AppCompatActivity(R.layout.activity_home)
This is the HomeFragment:
@AndroidEntryPoint
class MainFragment : Fragment(R.layout.fragment_main) {
private val binding by viewBinding(FragmentMainBinding::bind)
private val viewModel by viewModels<MainViewModel>()
private val articlesAdapter = ArticlesAdapter(::onSubscriptionClicked)
private lateinit var layoutManager: LinearLayoutManager
override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle)
setupViews()
setupViewModel()
setupRecyclerView()
}
private fun setupViews() {
binding.toolbar.title = getString(R.string.app_name)
binding.fab.setOnClickListener {
viewModel.intent.offer(MainViewModel.Intent.SearchClicked)
}
}
private fun setupViewModel() {
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
viewModel.feedFlow
.onEach(articlesAdapter::submitList)
.launchIn(lifecycleScope)
}
private fun setupRecyclerView() {
layoutManager = LinearLayoutManager(requireContext())
binding.recycler.layoutManager = layoutManager
binding.recycler.adapter = articlesAdapter
binding.recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val canScroll = recyclerView.canScrollVertically(-1)
binding.toolbar.isLifted = canScroll
}
})
}
private fun onSubscriptionClicked(article: Article) {
viewModel.intent.offer(MainViewModel.Intent.ItemClicked(article))
}
private fun handleState(state: MainViewModel.State) = when (state) {
NavigateToSearch -> findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
is FeedReady -> binding.progress.isVisible = false
Loading -> binding.progress.isVisible = true
is NavigateToArticle -> {
// works
// findNavController().navigate(
// R.id.articleFragment,
// bundleOf("articleLink" to state.link)
// )
}
}
}
And this is the XML for it:
<?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:clipChildren="false"
android:clipToPadding="false"
tools:context=".presentation.main.MainFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomNav"
app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:listitem="@layout/item_article_big" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard"
android:text="Add Feed"
android:textAlignment="center"
app:icon="@drawable/ic_add"
app:layout_constraintBottom_toTopOf="@id/bottomNav"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="@menu/menu_main" />
<tgo1014.news.presentation.customview.LiftableToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="@id/toolbar"
app:layout_constraintTop_toBottomOf="@id/toolbar"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
Solution
the error is due to the lifecycle. Replace this:
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
by
viewModel.state
.onEach(::handleState)
.launchIn(viewLifecycleOwner.lifecycleScope)
Answered By - Sinner of the System
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.