График навигации Android с проблемой навигации по фрагменту navviewholder при навигации с использованием элемента щелчка по списку
У меня есть очень простой вариант использования, который, к моему удивлению, не работает.
У меня есть контроллер навигации нижнего вида с двумя фрагментами: фрагментом списка и подробным фрагментом. Когда я перехожу на страницу фрагмента подробностей, у меня нет проблем с возвратом назад.
Когда я перехожу к фрагменту подробностей, явно используя обработчик щелчка элемента в представлении recyclerview, я больше не могу вернуться к первой вкладке, вкладке списка, используя нижнюю навигацию.
Вот мой навигационный график
<?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"
android:id="@+id/job_nav_graph"
app:startDestination="@id/jobsListFragment">
<fragment
android:id="@+id/jobsListFragment"
android:name="com.plcoding.posterpalfeature.ui.fragments.JobsListFragment"
android:label="JobsListFragment" >
<action
android:name="listToDetail"
android:id="@+id/action_jobsListFragment_to_jobDetailFragment"
app:destination="@id/jobDetailFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right">
</action>
</fragment>
<fragment
android:id="@+id/jobDetailFragment"
android:name="com.plcoding.posterpalfeature.ui.fragments.JobDetailFragment"
android:label="JobDetailFragment" >
<action
android:id="@+id/action_jobDetailFragment_to_jobsListFragment"
app:destination="@id/jobsListFragment"
app:enterAnim="@anim/slide_in_left"
app:exitAnim="@anim/slide_out_right"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
</navigation>
основная деятельность
<layout>
<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"
tools:context="com.plcoding.posterpalfeature.ui.activity.MainActivity">
<FrameLayout
android:id="@+id/flFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:id="@+id/navHostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/job_nav_graph" />
</FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="56dp"
app:menu="@menu/bottom_navigation_menu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Подробности о вакансии
<layout>
<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">
<TextView
android:id="@+id/txt_job_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Fragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Список вакансий
<?xml version="1.0" encoding="utf-8"?>
<layout>
<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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_jobs_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
обратный вызов элемента, который не позволяет мне использовать нижнюю навигацию для возврата после использования для перехода обратно к списку заданий после использования для перехода к деталям задания
private fun setupItemClickListener() {
jobsAdapter.setOnItemClickListener {
val action = JobsListFragmentDirections.actionJobsListFragmentToJobDetailFragment().setJobId(it.job.job_id.toInt())
findNavController().navigate(action)
}
}
Список заданийФрагмент
androidx.navigation.fragment.findNavController
//import com.plcoding.multipleroomtables.databinding.FragmentJobListBinding
import com.plcoding.posterpalfeature.api.Resource
import com.plcoding.posterpalfeature.repo.JobsRepository
import com.plcoding.posterpalfeature.ui.activity.MainActivity
import com.plcoding.posterpalfeature.ui.MainViewModel
import com.plcoding.posterpalfeature.ui.adapters.JobAdapter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class JobsListFragment : Fragment(R.layout.fragment_job_list){
companion object {
const val BUNDLE_KEY = "job_id"
const val TAG = "JobsListFragment"
}
@Inject
lateinit var repo : JobsRepository
lateinit var viewModel: MainViewModel
lateinit var binding: FragmentJobListBinding
lateinit var jobsAdapter : JobAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentJobListBinding.bind(requireView())
viewModel = (activity as MainActivity).mainViewModel
jobsAdapter = JobAdapter()
setupRecyclerView(binding.rvJobsList)
setupItemClickListener()
listenToApiLiveData()
viewModel.getJobsList()
}
private fun setupItemClickListener() {
jobsAdapter.setOnItemClickListener {
val action = JobsListFragmentDirections.actionJobsListFragmentToJobDetailFragment().setJobId(it.job.job_id.toInt())
findNavController().navigate(action)
}
}
private fun listenToApiLiveData() {
viewModel.jobsListUpdate.observe(viewLifecycleOwner, Observer { response ->
when(response) {
is Resource.Success -> {
hideProgressBar()
hideErrorMessage()
response.data?.let { jobsResponse ->
jobsAdapter.differ.submitList(jobsResponse.jobs)
jobsAdapter.notifyDataSetChanged()
}
}
is Resource.Error -> {
hideProgressBar()
response.message?.let { message ->
Toast.makeText(activity, "An error occured fetching jobs: $message", Toast.LENGTH_LONG).show()
}
}
is Resource.Loading -> {
showProgressBar()
}
}
} )
}
private fun showProgressBar() {
// paginationProgressBar.visibility = View.VISIBLE
// isLoading = true
}
private fun hideErrorMessage() {
}
private fun hideProgressBar() {
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
activity?.lifecycleScope?.launch {
val jobslist = repo.getAllJobs()
recyclerView.apply {
adapter = jobsAdapter
layoutManager = LinearLayoutManager(activity)
//x addItemDecoration(DividerItemDecoration(this.context, DividerItemDecoration.VERTICAL))
}
jobsAdapter.differ.submitList(jobslist)
}
}
}
РаботаДетальФрагмент
package com.plcoding.posterpalfeature.ui.fragments
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import com.plcoding.multipleroomtables.R
import com.plcoding.multipleroomtables.databinding.FragmentJobDetailBinding
//import com.plcoding.multipleroomtables.databinding.FragmentJobDetailBinding
import com.plcoding.posterpalfeature.repo.relations.jobworkerposter.JobPW
import com.plcoding.posterpalfeature.ui.activity.MainActivity
import com.plcoding.posterpalfeature.ui.MainViewModel
class JobDetailFragment: Fragment(R.layout.fragment_job_detail) {
companion object {
const val TAG = "JobDetailFragment"
}
val args: JobDetailFragmentArgs by navArgs()
lateinit var binding: FragmentJobDetailBinding
lateinit var viewModel: MainViewModel
lateinit var jobPW: JobPW
var job_id: Int = -1
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentJobDetailBinding.bind(requireView())
job_id = args.jobId
viewModel = (activity as MainActivity).mainViewModel
jobPW = viewModel.getJobById(job_id.toLong())
jobPW.job
jobPW.posters
jobPW.workers
Log.d(TAG, "job_Id by sage args args.jobId ${job_id}, posters size ${jobPW.posters.size} " +
" workers size ${jobPW.workers.size} ")
}
}
Это очень просто и должно работать.
Есть идеи, что попробовать дальше?
1 ответ
Значит проблема была в бэкстеке. Мне пришлось добавить popUp и popUpInclusive в XML-фрагмент навигации.
<action
android:id="@+id/action_jobsListFragment_to_jobDetailFragment"
app:destination="@id/jobDetailFragment"
app:popUpTo="@id/jobsListFragment"
app:popUpToInclusive="true" />
Это действительно не было ясно из документации и кодовых лабораторий, это должно быть поведение по умолчанию для BottomNavigationView. Если кто-то может прокомментировать, как работают атрибуты popUp, мы будем очень признательны. Спасибо за поддержку в комментариях :)