使用导航 UI 组件在片段之间传递数据 [英] Passing data between fragment using navigation UI component

查看:30
本文介绍了使用导航 UI 组件在片段之间传递数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在片段之间传递数据,我有一个 CharactersFragment 和一个 CharacterDetailFragment,在 CharactersFragment 中我有一个回收器视图,当我点击一个项目/行时,应该将字符详细信息发送到 ChracterDetailFragment.

I want to pass data between fragments, I have a CharactersFragment and a CharacterDetailFragment, in CharactersFragment I have a recycler view and when I click a item/row, the character details should be sent to ChracterDetailFragment.

我正在使用导航 UI 组件,目前我只将字符名称作为字符串传递.

I am using navigation UI component, and I am at the moment passing only character name as string.

我有一个角色对象,我可以通过 safeargs 传递角色对象吗,我读到这不是一个正确的方法.

I have a character object, can I pass character object through safeargs, I read that it is not a right approach.

我应该将角色的 id 传递给另一个片段并在详细片段中检索该 id 的数据吗?

should I just pass id of the character to the other fragment and retrieve data for that id in the detail fragment?

请问解决此问题的最佳方法是什么.

what is the best approach to solve this please.

这是我目前编写的代码

非常感谢您提前R

导航图

<?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/charactersFragment">

    <fragment
        android:id="@+id/charactersFragment"
        android:name="com.example.breakingbad.CharactersFragment"
        android:label="fragment_characters"
        tools:layout="@layout/fragment_characters" >
        <action
            android:id="@+id/action_charactersFragment_to_characterDetailFragment"
            app:destination="@id/characterDetailFragment" />
    </fragment>
    <fragment
        android:id="@+id/characterDetailFragment"
        android:name="com.example.breakingbad.CharacterDetailFragment"
        android:label="fragment_character_detail"
        tools:layout="@layout/fragment_character_detail" >
        <argument
            android:name="character"
            app:argType="string" />
    </fragment>
</navigation>

CharactersFragment - 我有一个 recyclerview,当单击一行并导航到详细信息屏幕时,我正在分配一个适配器并传递字符名称

CharactersFragment - I have a recyclerview and I am assigning a adapter and passing character name when a row is clicked and navigating to detail screen

private fun initView() {
        val recyclerView = binding.recyclerView
        recyclerView.layoutManager = LinearLayoutManager(activity)
        val decoration = DividerItemDecoration(activity, DividerItemDecoration.VERTICAL)
        recyclerView.addItemDecoration(decoration)

        recyclerAdapter = RecyclerViewAdapter()
        recyclerView.adapter = recyclerAdapter
        recyclerAdapter.onItemClick = { character ->
            val action = CharactersFragmentDirections.actionCharactersFragmentToCharacterDetailFragment(character.name)
            findNavController().navigate(action)
        }
    }

RecyclerViewAdapter

RecyclerViewAdapter

class RecyclerViewAdapter: RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>() {

    var items = ArrayList<Character>()
    var onItemClick: ((Character) -> Unit)?  = null
    var itemPosition = 0

    fun setUpdatedData(items: ArrayList<Character>) {
        this.items = items
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.characters_row, parent, false)

        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        itemPosition = position
        holder.bind(items.get(position))
    }

    override fun getItemCount(): Int {
        return items.size
    }

    inner class MyViewHolder(view: View): RecyclerView.ViewHolder(view) {
        val tvName = view.findViewById<TextView>(R.id.tvName)

        init {
            view.setOnClickListener {
                Log.d("adapter", "item clicked")
                onItemClick?.invoke(items[this.layoutPosition])
            }
        }

        fun bind(data: Character) {
            tvName.text = data.name
        }
    }
}

CharacterDetailFragment

CharacterDetailFragment

class CharacterDetailFragment : Fragment() {

    val args: CharacterDetailFragmentArgs by navArgs()

    private var _binding: FragmentCharacterDetailBinding? = null
    private val binding get() = _binding!!

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

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCharacterDetailBinding.inflate(inflater, container, false)
        val view = binding.root

        binding.tvNumber.text = args.character.toString()
        return view
    }
}

ref 的字符

data class Character(
    val name: String,
    val img: String,
    val occupation: ArrayList<String>,
    val status: String,
    val nickname: String,
    val appearance: ArrayList<Int>
)

谢谢R

推荐答案

无论哪种方式都可以.这两种方法都很好.但是由于您只传递一个对象或希望在下一个 Fragment 中只有一个对象,您应该选择安全的 args 模式.原因是如果您只传递 id ,然后该 id 将获取数据,则会增加开销.因此,要删除它,最好使用安全 args .此外,它很容易维护 safeArgs 进程,因为它大部分时间保存您的活动/片段数据在后台与其他需要再次调用 api/数据库的情况不同.但是,如果您根据 id 获取对象列表,那么您应该使用传递 id 并从 api/database 方式获取数据.

You can do it either way . Both approaches are fine . But since you are passing only one object or want to have only one object in the next Fragment , you should go for safe args pattern . The reason is there will be an overhead added if you just pass the id and then that id will fetch the data . So to remove that it is preferable to use safe args . Also it is easy to maintain the safeArgs process since it most of the time saves your data on activity / fragment being in the background unlike the other wherein you need to call the api / database again . But if your are getting a list of objects based on the id , then you should do it using the passing the id and getting the data from api/database way .

由于您在获取数据列表的帖子中没有提到任何地方,下面是使用 SafeArgs 的方法.

Since you have no where mentioned in your post of getting a list of Data , below is the way of doing it using SafeArgs.

第 1 步:使您的数据类 Parcelable :

Step 1: Make your data class Parcelable :

@Parcelize
data class Character(
    val name: String,
    val img: String,
    val occupation: ArrayList<String>,
    val status: String,
    val nickname: String,
    val appearance: ArrayList<Int>
):Parcelable

第 2 步:然后在您的导航图中,您可以通过以下方式声明一个 Parcelable 对象作为导航图中的参数发送到下一个片段.选择类型为 Custom Parcelable,然后选择您的类并将其命名为字符,以便将来更好地阅读.

Step 2 : Then in your nav graph you declare an parcelable object to be send to the next fragment as an argument in the nav graph the following way. Select the type as Custom Parcelable and then select your class and also name it as character for better readability in the future .

第 3 步:现在在您的 Fragment 中,获取您要发送的数据类,并在您导航到下一个 Fragment 时将其传入.

Step 3 : Now in your fragment , get the data class you want to send and pass it in when you are navigating to the next Fragment .

 val action = SenderFragmentDirections.senderFragmentoRecieverFragment(character )
findNavController().navigate(action)

第 4 步:在您尝试获取 args 的片段中,如下声明一个 top 变量,然后在您的 onCreate()/onViewCreated() 中获取数据.

Step 4 : In the fragment that you are trying to get the args declare a top variable as follows and then in your onCreate() / onViewCreated() get the data .

    private val args by navArgs<ReceiverFragmentArgs>()

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
  args.character.whatever 
//And do your further needs     
}

记住在 gradle 中正确设置依赖项(应用程序和项目级别)

这篇关于使用导航 UI 组件在片段之间传递数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆