【问题标题】:Passing data between fragment using navigation UI component使用导航 UI 组件在片段之间传递数据
【发布时间】:2021-08-29 13:31:24
【问题描述】:

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

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

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

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

请问解决这个问题的最佳方法是什么。

这是我目前写的代码

非常感谢您提前 回复

导航图

<?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,我正在分配一个适配器并在单击一行并导航到详细信息屏幕时传递字符名称

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

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

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
    }
}

参考字符

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

谢谢 回复

【问题讨论】:

    标签: android kotlin android-jetpack android-jetpack-navigation


    【解决方案1】:

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

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

    第 1 步: 使您的数据类 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 步:然后在您的导航图中,您声明一个可打包对象作为导航图中的参数发送到下一个片段,方法如下。选择类型为 Custom Parcelable,然后选择您的类并将其命名为字符,以便将来更好地阅读。

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

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

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

        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 中正确设置依赖项(应用和项目级别)

    【讨论】:

      猜你喜欢
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      • 2020-09-24
      • 2022-01-05
      • 1970-01-01
      • 2016-11-21
      • 2021-09-16
      相关资源
      最近更新 更多