繁体   English   中英

Kotlin:如何使用视图模型/接口将数据从片段中的 recyclerview 传递到另一个片段?

[英]Kotlin: How to pass data from recyclerview in fragment to another fragment using viewmodel/interface?

我找不到使用viewmodel中的视图模型或接口将数据从 recyclerview 适配器传递到片段的kotlin 我试图只使用一个包,但我在接收片段中收到了一个 null 包。 这是我的Recyclerview 适配器代码片段。

class QnAMyProfileEditRecyclerViewAdapter(private val context: Context) : RecyclerView.Adapter<QnAMyProfileEditRecyclerViewAdapter.Holder>() {


    private var currentUserQnADataMyProfileEdit = emptyList<QnAData>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {

        val view: View = if (viewType == R.layout.rv_item_qn_a_my_profile) {

            LayoutInflater.from(parent.context)
                .inflate(R.layout.rv_item_qn_a_my_profile, parent, false)

        } else {

            LayoutInflater.from(parent.context)
                .inflate(R.layout.rv_footer_new_qna_my_profile, parent, false)

        }
        return Holder(view)
    }

    override fun getItemCount(): Int {
        return currentUserQnADataMyProfileEdit.size + 1
    }

    //implement Floating Action Button at the bottom of the recyclerview
    override fun getItemViewType(position: Int): Int {

        return if (position == currentUserQnADataMyProfileEdit.size) {
            R.layout.rv_footer_new_qna_my_profile
        } else {
            R.layout.rv_item_qn_a_my_profile
        }
    }

    override fun onBindViewHolder(holder: Holder, position: Int) {

        if (position == currentUserQnADataMyProfileEdit.size) {
            holder.viewHolderNewQnA?.setOnClickListener {
                Toast.makeText(context, "New item intent", Toast.LENGTH_SHORT).show()
            }
        } else {
            //Normal bind for RecyclerView
            holder.bindData(currentUserQnADataMyProfileEdit[position])
            holder.viewHolderCRUDQnAMyProfile?.setOnClickListener {


                //Give QnACrud current QnAData --- send bundle
                val bundle = Bundle()
                bundle.putString(
                    "currentQnAQuestion",
                    currentUserQnADataMyProfileEdit[position].question
                )
                bundle.putString(
                    "currentQnAAnswer",
                    currentUserQnADataMyProfileEdit[position].answer
                )
                QnAMyProfileEditCRUDFragment().arguments = bundle
                val activity: AppCompatActivity = context as AppCompatActivity
                activity.supportFragmentManager.beginTransaction()
                    .add(R.id.cl_my_profile_edit, QnAMyProfileEditCRUDFragment())
                    .addToBackStack(null).commit()




            }
        }
    }


    fun setData(updateList: List<QnAData>) {
        this.currentUserQnADataMyProfileEdit = updateList
        notifyDataSetChanged()
    }

    inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {




        val viewHolderQuestion =
            itemView.findViewById(R.id.txt_question_qna_my_profile_edit) as TextView?
        val viewHolderAnswer =
            itemView.findViewById(R.id.txt_answer_qna_my_profile_edit) as TextView?

        val viewHolderNewQnA =
            itemView.findViewById(R.id.fab_new_qna_my_profile_edit) as FloatingActionButton?

        val viewHolderCRUDQnAMyProfile =
            itemView.findViewById(R.id.fab_crud_qna_my_profile_edit) as FloatingActionButton?


        //Bind data with inflaters
        fun bindData(currentUserInList: QnAData) {

            viewHolderQuestion?.text = currentUserInList.question
            viewHolderAnswer?.text = currentUserInList.answer
        }

    }
}

这是我的片段,它假设接收数据( bundle ):

class QnAMyProfileEditCRUDFragment : Fragment() {

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

        //Get bundle data and set Edit Text values


        val bundle:Bundle? = arguments //Bundle == null!!!!
        val qnaQuestionData: String? = bundle?.getString("currentQnAQuestion")
        val qnaAnswerData: String? = bundle?.getString("currentQnAAnswer")
        et_qna_question.setText(qnaQuestionData)
        et_qna_answer.setText(qnaAnswerData)


    }

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



        return inflater.inflate(R.layout.fragment_qn_a_my_profile_edit_c_r_u_d, container, false)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)


    }

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

        //Pop fragment if grey area(outside the box) is tapped
        imv_overlay.setOnClickListener {
            fragmentManager?.popBackStack()
        }
    }

}

QnAData是一个简单的data class answer question string type

尝试在您的片段中创建一个构造函数,然后 beginTransaction

val fragment = QnAMyProfileEditCRUDFragment.newInstance( 
currentUserQnADataMyProfileEdit[position].question, 
currentUserQnADataMyProfileEdit[position].answer)

activity.supportFragmentManager.beginTransaction()
                    .add(R.id.cl_my_profile_edit,fragment)
                    .addToBackStack(null).commit()

在 QnAMyProfileEditCRUDFragment 中,您可以只使用构造函数中的值

首先,需要对您的代码进行一些重构:

  1. 内部 class 可能导致 memory 泄漏,因此将 ViewHolder 更改为:
  2. 将您的点击监听器带入您的 ViewHolder

视图持有者

class MyViewHolder(...) : RecyclerView.ViewHolder(...) {

    fun bind(model: Model) {
        ...

        itemView.setOnClickListener {
            callback?.onSomeEventHappened(model)
            //you can also pass lambda here instead of using an interface for callback
        }

    }

}
  1. RecyclerViewAdapter 需要定义一个协议来和一个fragment进行通信:
class Adapter : RecyclerView.Adapter<T>() {

    interface callback {
        fun onSomeEventHappened()
    }


    private var callback: callback? = null

    
    fun setListener(listener: Callback) {
        callback = listener
    }

}
  1. 如果数据在两个片段之间共享,则使用SharedViewModel
  2. 如果您需要传递数据,您可以使用 AndroidNavigationCompoent arguments 或在创建片段时传递它们:
val SomeFragment = SomeFragment().apply {
    SomeFragment.arguments = ... //A bundle for example
}

假设您的 Fragment 容器活动和子 Fragment 共享 viewModel,您可以将相同的 viewModel 传递给您的 recyclerview 适配器。

class Activity: AppCompatActivity {
   private val viewModel: AnyViewModel by lazy { 
        //Initialization 
   }
   private val adapter = Adapter(viewModel)

   ...
}

class Adapter(viewModel: SomeViewModel) : RecyclerView.Adapter<T>() {

   ...

   override fun onBindViewHolder(holder: ViewHolder, position: Int) {
       holder.onBind(anyList[position])
   }

   inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
      ...


      fun onBind(data: SomeData) {
         btnSomeAction.setOnClickListener {
            //Here change respected data in viewModel or call some method
            //viewModel.anyObject = some_value
            //viewModel.anyMethodCall() 
         }
      }
   }
}

现在您可以访问适配器中的 viewModel 并使用它从 Activity 或 Fragment 更新数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM