如何在 kotlin 中使用 jetpack 导航到达上一个片段?

How to get to the previous fragment using jetpack navigation in kotlin?

我正在制作一个包含两个片段的应用程序,它们是 home-fragment 和 youtube-fragment。当我按下“搜索”按钮时,我可以正确地找到 youtube-fragment。但是,当我按下后退按钮(phone 上的后退按钮而不是工具栏中的后退箭头)时,我只是退出应用程序而没有收到任何错误或警告。我想在按下后退按钮后返回主页片段。

这是我的两个片段的代码:

homeFragment

package com.example.signlanguage_new

import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.GridLayout
import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.example.signlanguage_new.databinding.FragmentHomeBinding

class HomeFragment : Fragment() {
    private val viewModel: MyViewModel by activityViewModels {
        MyViewModelFactory(
            (activity?.application as SignLanguageApplication).database.VideoDao()
        )
    }
    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.result.observe(viewLifecycleOwner)
        {
            if(it==null) {
                Toast.makeText(requireContext(), "查無資料", LENGTH_SHORT).show()
            }
            else
            {
                val action=HomeFragmentDirections.actionHomeFragmentToYoutubeFragment()
                findNavController().navigate(action)
            }
        }
        super.onViewCreated(view, savedInstanceState)
        binding.apply {
            searchBtn.setOnClickListener {
                val search=binding.search.text.toString()
                if(search=="")
                {
                    Toast.makeText(requireContext(), "請輸入關鍵字", LENGTH_SHORT).show()
                }
                else
                {
                    viewModel.searchVideo(search)
                }
            }
        }
        val adapter=homeButtonAdapter{
            viewModel.category(it)
        }
        binding.recyclerView.adapter=adapter
        binding.recyclerView.layoutManager=GridLayoutManager(this.context,2)
    }
}

youtubeFragment

package com.example.signlanguage_new

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.signlanguage_new.data.Video
import com.example.signlanguage_new.databinding.FragmentYoutubeBinding

class youtubeFragment : Fragment() {
    private val viewModel: MyViewModel by activityViewModels {
        MyViewModelFactory(
            (activity?.application as SignLanguageApplication).database.VideoDao()
        )
    }
    private var _binding: FragmentYoutubeBinding? = null
    private val binding get() = _binding!!
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentYoutubeBinding.inflate(inflater, container, false)
        return binding.root
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val Dataset= viewModel.result.value
        binding.recyclerView.adapter= Dataset?.let {
            VideoAdapter(requireContext(),
                it,this.lifecycle)
        }
        binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
    }
}

这是 nav_graph 和我的 mainActivity:

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"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.signlanguage_new.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_homeFragment_to_youtubeFragment"
            app:destination="@id/youtubeFragment"
            app:popUpTo="@id/homeFragment"
            app:popUpToInclusive="true" />
    </fragment>
    <fragment
        android:id="@+id/youtubeFragment"
        android:name="com.example.signlanguage_new.youtubeFragment"
        android:label="fragment_youtube"
        tools:layout="@layout/fragment_youtube" />
</navigation>

MainActivity

package com.example.signlanguage_new

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI.setupActionBarWithNavController

class MainActivity : AppCompatActivity(R.layout.activity_main) {

    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Retrieve NavController from the NavHostFragment
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController
        // Set up the action bar for use with the NavController
        setupActionBarWithNavController(this, navController)
    }

    /**
     * Handle navigation when the user chooses Up from the action bar.
     */
    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

我想这可能与我在 youtube-fragment 中的 recyclerview 适配器有关,因为我提供了生命周期作为它的参数。

这里是:

视频适配器

package com.example.signlanguage_new

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.signlanguage_new.data.Video
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView

class VideoAdapter (private val context: Context, private val dataset:List<Video>, private val lifecycle: Lifecycle) :RecyclerView.Adapter<VideoAdapter.ItemViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {

        val youTubePlayerView: YouTubePlayerView = LayoutInflater.from(parent.context).inflate(R.layout.videolistitem,parent,false) as YouTubePlayerView
        lifecycle.addObserver(youTubePlayerView)
        return ItemViewHolder(youTubePlayerView)
    }

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val current=dataset[position]
        holder.setIsRecyclable(false)
        holder.loadVideo(current.ytId)
    }
    
    override fun getItemCount(): Int {
        return dataset.size
    }
    class ItemViewHolder(playerView: YouTubePlayerView) :
        RecyclerView.ViewHolder(playerView) {
        val youTubePlayerView: YouTubePlayerView = playerView
        var youTubePlayer: YouTubePlayer? = null
        var currentVideoId: String? = null
        
        fun loadVideo(videoId: String?) {
            currentVideoId = videoId
            if (youTubePlayer == null) return
            if (videoId != null) {
                youTubePlayer!!.cueVideo(videoId, 0F)
            }
        }
        init {
            youTubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
                override fun onReady(initializedYouTubePlayer: YouTubePlayer) {
                    youTubePlayer = initializedYouTubePlayer
                    currentVideoId?.let {
                        youTubePlayer!!.cueVideo(it, 0F)
                    }
                }
            })
        }
    }
}

有谁知道我怎样才能到达主页片段而不是离开应用程序?

当您将 app:popUpTo="@id/homeFragment", app:popUpToInclusive="true" 添加到您的导航操作时,这意味着您要从返回堆栈中删除 homeFragment。本质上意味着当您按下后退时,homeFragment 将不再存在,如果您希望后退按钮将您带到 homeFragment,您需要将操作更新为

<action
      android:id="@+id/action_homeFragment_to_youtubeFragment"
      app:destination="@id/youtubeFragment" />