График навигации 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, мы будем очень признательны. Спасибо за поддержку в комментариях :)

Другие вопросы по тегам