【问题标题】:How to share data between Two Fragments and ListViewAdapter (RecyclerView)如何在两个 Fragments 和 ListViewAdapter (RecyclerView) 之间共享数据
【发布时间】:2021-05-29 11:36:53
【问题描述】:

我需要将数据从 ListAdapter(recyclerView 中单击的项目)传递到第二个 Fragment。我试过这个(下面的代码)但它没有用。我是新手,但我真的不明白。感谢您的任何回答。

我有这个 ViewModel:

    class ContactItemViewModel: ViewModel() {

    private val mutableContactItem = MutableLiveData<Contact>()
    val selectedItem: LiveData<Contact> get() = mutableContactItem

    fun selectContactItem(_item: Contact){
        mutableContactItem.value = _item
    }

}

我有这个人物片段

class PeopleFragment : Fragment() {
    companion object {
        @JvmStatic
        fun newInstance() = PeopleFragment()
    }

    private lateinit var peopleFragmentBinding: FragmentPeopleBinding
    private var selectedMenuItem: Int = 0
    private val contactItemViewModel: ContactItemViewModel by activityViewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        peopleFragmentBinding = FragmentPeopleBinding.inflate(layoutInflater)
        setHasOptionsMenu(true)

        setListAdapter()
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater){
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.menu_overflow, menu)
        val listMenuItem = menu.findItem(R.id.show_list)
        val gridMenuItem = menu.findItem(R.id.show_list)
    }

    override fun onPrepareOptionsMenu(menu: Menu) {
        super.onPrepareOptionsMenu(menu)
        when(selectedMenuItem){
            0 -> {
                menu.findItem(R.id.show_list).isVisible = false
                menu.findItem(R.id.show_grid).isVisible = true
            }
            1 -> {
                menu.findItem(R.id.show_list).isVisible = true
                menu.findItem(R.id.show_grid).isVisible = false
            }
        }
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when(item.itemId){
            R.id.show_grid -> {
                peopleFragmentBinding.rvPeople.layoutManager = GridLayoutManager(context, 5)
                selectedMenuItem = 1
                setGridAdapter()
                true
            }
            R.id.show_list -> {
                peopleFragmentBinding.rvPeople.layoutManager = LinearLayoutManager(context)
                selectedMenuItem = 0
                setListAdapter()
                true
            }
            else -> {
                super.onOptionsItemSelected(item)
            }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        return peopleFragmentBinding.root
    }

    private fun setListAdapter(){
        GlobalScope.launch {
            var dataset: List<Contact> = Datasource().loadContacts()
            withContext(Dispatchers.Main){
                peopleFragmentBinding.rvPeople.adapter = ListItemAdapter(requireContext(), dataset, contactItemViewModel)
            }
        }
    }

    private fun setGridAdapter(){
        GlobalScope.launch {
            var dataset: List<Contact> = Datasource().loadContacts()
            withContext(Dispatchers.Main){
                peopleFragmentBinding.rvPeople.adapter = GridItemAdapter(requireContext(), dataset)
            }
        }
    }
}

第二个DetaildInfo片段:

class DetailsFragment() : Fragment() {
    private lateinit var detailsFragmentBinding: FragmentDetailsBinding
    private lateinit var contactItem: Contact
    private val contactItemViewModel: ContactItemViewModel by activityViewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        detailsFragmentBinding = FragmentDetailsBinding.inflate(layoutInflater)


    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val contactItemViewModel = ViewModelProvider(requireActivity()).get(ContactItemViewModel::class.java)
        contactItemViewModel.selectedItem.observe(viewLifecycleOwner, Observer {
            setDetailedInfo(it)
        })
        return inflater.inflate(R.layout.fragment_details, container, false)
    }

    private fun setDetailedInfo(item: Contact){
        val transformation = CircleTransformation()
        detailsFragmentBinding.tvName.text = item.name
        detailsFragmentBinding.tvEmail.text = item.email
        Picasso.get()
            .load(item.getGravatarUri())
            .fit().centerCrop()
            .placeholder(R.mipmap.ic_contact)
            .transform(transformation)
            .into(detailsFragmentBinding.ivAvatar)
    }

    /*companion object {

        @JvmStatic
        fun newInstance() = DetailsFragment(_item =)
    }*/
}

还有这个适配器:

class ListItemAdapter(
    private val context: Context,
    private val dataset: List<Contact>,
    private var contactItemViewModel: ContactItemViewModel
) : RecyclerView.Adapter<ListItemAdapter.ItemViewHolder>() {

    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
        val tvName: TextView = view.findViewById(R.id.tv_name)
        val ivAvatar: ImageView = view.findViewById(R.id.iv_avatar)

    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        if(contactItemViewModel == null){
            contactItemViewModel = ViewModelProvider((recyclerView.context as ViewModelStoreOwner)!!).get(
                ContactItemViewModel::class.java
            )
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        val adapterLayout = LayoutInflater.from(parent.context).inflate(
            R.layout.list_item, parent, false
        )

        return ItemViewHolder(adapterLayout)
    }

    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        val transformation = CircleTransformation()
        holder.tvName.text = item.name
        Picasso.get()
            .load(item.getGravatarUri())
            .fit().centerCrop()
            .placeholder(R.mipmap.ic_contact)
            .transform(transformation)
            .into(holder.ivAvatar)

        holder.itemView.setOnClickListener { v ->
            val activity = v!!.context as AppCompatActivity
            val bundle: Bundle = Bundle()
            contactItemViewModel.selectContactItem(item)
            val detailsFragment = DetailsFragment()
            activity.supportFragmentManager.beginTransaction()
                .replace(R.id.fl_content, detailsFragment)
                .addToBackStack("detailsFragmentBackStack").commit()
        }
    }

    override fun getItemCount(): Int = dataset.size

}

ContactsActivity:

class ContactsActivity : AppCompatActivity() {

    private lateinit var contactsActivityBinding :ActivityContactsBinding
    private val contactItemViewModel: ContactItemViewModel by viewModels()

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

        contactsActivityBinding = ActivityContactsBinding.inflate(layoutInflater)
        setContentView(contactsActivityBinding.root)

        if (savedInstanceState == null) {
            val manager = supportFragmentManager
            val transaction = manager.beginTransaction()
            transaction.replace(contactsActivityBinding.flContent.id, PeopleFragment.newInstance())
            transaction.commit()
        }
    }
}

【问题讨论】:

    标签: android kotlin android-fragments android-recyclerview android-livedata


    【解决方案1】:

    我觉得问题出在这段代码中:

      holder.itemView.setOnClickListener { v ->
                val activity = v!!.context as AppCompatActivity
                val bundle: Bundle = Bundle()
                contactItemViewModel.selectContactItem(item)
    
               //You are creating the fragment here so old viewmodel instance will be destroyed as new viewModel instance will get created.
               
             //What is the use of below code?
    
               // val detailsFragment = DetailsFragment()
                //activity.supportFragmentManager.beginTransaction()
                  //  .replace(R.id.fl_content, detailsFragment)
                    //.addToBackStack("detailsFragmentBackStack").commit()
    
        //By commenting above line your viewModel function should be called and data should be passed
            }
    

    如果要创建新的 Fragment,请在 Fragment 类中进行,如下所示:

    fun selectContactItem(_item: Contact){
            mutableContactItem.value = _item
         //observe another mutable live data and then do creation of new fragment
        }
    
    

    这应该可以解决您的数据不被传递的问题

    【讨论】:

    • 我用这段代码新建了一个fragment,放到Activity中的fl_content中
    猜你喜欢
    • 1970-01-01
    • 2013-02-25
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多