如何将数据从适配器传递到片段?

How to pass data from adapter to fragment?

我一直在尝试将数据(用户的电子邮件和 phone)从我的适配器传递到我的片段。根据我在网上阅读的内容,我应该为此使用一个接口,但我仍然无法将数据放入我的片段中。任何人都可以按步骤解释我应该如何添加接口以及如何将数据从我的适配器放入我的接口以便我可以在我的片段中调用它。或者还有另一种方法可以将数据从我的适配器传递到我的片段。下面是我的适配器和我的片段。

适配器:

package ie.wit.savvytutor.adapters
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import ie.wit.savvytutor.R
import ie.wit.savvytutor.activity.MainActivity
import ie.wit.savvytutor.fragments.ViewChatFragment
import ie.wit.savvytutor.models.UserModel


class UserAdapter(private val userList: ArrayList<UserModel>, val context: Context) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
    val itemView =
        LayoutInflater.from(parent.context).inflate(R.layout.user_layout, parent, false)
    return UserViewHolder(itemView)
}


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

    val username: TextView = itemView.findViewById(R.id.userNameView)

}

override fun onBindViewHolder(holder: UserViewHolder, position: Int, ) {
    val currentItem = userList[position]



    holder.username.text = currentItem.email
    holder.itemView.setOnClickListener {
        println(currentItem)

        




        val optionsFrag = ViewChatFragment()
        (context as MainActivity).getSupportFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, optionsFrag, "OptionsFragment").addToBackStack(
                null
            )
            .commit()
    }


}

override fun getItemCount(): Int {
    return userList.size

}

}

片段

package ie.wit.savvytutor.fragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup    
import androidx.annotation.Nullable
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import ie.wit.savvytutor.R
import ie.wit.savvytutor.adapters.UserAdapter
import ie.wit.savvytutor.models.UserModel

class TutorChatFragment : Fragment() {

private lateinit var userRecyclerView: RecyclerView
private lateinit var userArrayList: ArrayList<UserModel>
private lateinit var dbRef: DatabaseReference
private lateinit var mAuth: FirebaseAuth



override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    dbRef = FirebaseDatabase.getInstance("DATABASE LINK").getReference("Users").ref
    mAuth = FirebaseAuth.getInstance()
}

@Nullable
override fun onCreateView(
    inflater: LayoutInflater,
    @Nullable container: ViewGroup?,
    @Nullable savedInstanceState: Bundle?
): View {
    //inflate the fragment layout
    val root = inflater.inflate(R.layout.tutor_chat_fragment, container, false)
    userRecyclerView = root.findViewById(R.id.userListView)
    userRecyclerView.layoutManager = LinearLayoutManager(context)
    userRecyclerView.setHasFixedSize(true)


    userArrayList = arrayListOf<UserModel>()
    getUser()
    return root
}

private fun getUser() {

    userArrayList.clear()

    dbRef.addValueEventListener(object: ValueEventListener{
        override fun onDataChange(snapshot: DataSnapshot) {
            for (postSnapshot in snapshot.children) {
                val currentUser = postSnapshot.getValue(UserModel::class.java)

                //BUG FIX 1.26.13

                val email = currentUser?.email
                if (email != null) {
                    userArrayList.add(currentUser)
                }

                userRecyclerView.adapter?.notifyDataSetChanged()
                userRecyclerView.adapter = context?.let { UserAdapter(userArrayList, it) }

            }
        }

        override fun onCancelled(error: DatabaseError) {
            TODO("Not yet implemented")
        }

    })

}

}

如果你想使用一个接口,你只需要定义一个函数来接收你的数据,让片段实现它,然后将片段作为该接口的实现传递给适配器:

data class UserData(val email: String, val phone: String)

class UserAdapter(
    private val userList: ArrayList<UserModel>,
    val context: Context,
    val handler: UserAdapter.Callbacks // added this here, so you're passing it in at construction
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {

    ...

    private fun doWhatever(email: String, phone: String) {
        // pass the data to the handler (which will probably be your Fragment)
        handler.handleUserData(UserData(email, phone))
    }

    // nested inside the UserAdapter class to keep things tidy
    interface Callbacks {
        fun handleUserData(data: UserData)
    }
}

然后在片段中:

// add the Callbacks interface type
class TutorChatFragment : Fragment(), UserAdapter.Callbacks {
    override fun onCreateView(
        inflater: LayoutInflater,
        @Nullable container: ViewGroup?,
        @Nullable savedInstanceState: Bundle?
    ): View {
        ...
        userRecyclerView.layoutManager = LinearLayoutManager(context)

        // set up the adapter here, passing this fragment as the Callbacks handler
        userRecyclerView.adapter = UserAdapter(userArrayList, context, this)
        ...
    }

    // interface implementation
    override fun handleUserData(data: UserData) {
        // whatever
    }
}

就是这样。您没有硬编码对特定片段类型的依赖,只是接口,这个片段实现了它,所以它可以传递自己。


一种更 Kotliny 的方式是忽略接口而只传递一个函数

class UserAdapter(
    private val userList: ArrayList<UserModel>,
    val context: Context,
    val handler: (UserData) -> Unit // passing a function that takes a UserData instead
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {

    ...

    private fun doWhatever(email: String, phone: String) {
        // call the handler function with your data (you can write handler.invoke() if you prefer)
        handler(UserData(email, phone))
    }
}
// no interface this time
class TutorChatFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        @Nullable container: ViewGroup?,
        @Nullable savedInstanceState: Bundle?
    ): View {
        ...
        userRecyclerView.layoutManager = LinearLayoutManager(context)

        // pass in a handler function
        userRecyclerView.adapter = UserAdapter(userArrayList, context) { userData ->
            handleUserData(userData)
        }
        // or if you're just passing it to that function down there,
        // you could do UserAdapter(userArrayList, context, ::handleUserData)
        // and pass the function reference
        ...
    }

    // might be convenient to still do this in its own function
    private fun handleUserData(data: UserData) {
        // whatever
    }
}

理想情况下,您应该按照我在此处所做的操作 - 在设置期间创建适配器 一次,并在其上设置一个允许您更新它的功能。每次获取数据时,您的代码都会创建一个新代码。尽管

您的另一个选择是使用适配器和片段都可以访问的视图模型,但这就是您执行 interface/callback 方法的方式

实际上,有一种非常简单的方法可以将数据从您的适配器获取到您的片段或 activity。它使用高阶函数调用。 在你的适配器中 在您的适配器中添加高阶函数。

class UserAdapter(private val userList: ArrayList<UserModel>, val context: Context) :
RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
//your rest of the adapter's code

private var onItemClickListener:((UserModel)->Unit)? = null
fun setOnItemClickListener(listener: (UserModel)->Unit) {
     onItemClickListener = listener
   }
}

在你的 UserViewHolder 中

val rootView = itemView.rootView

在你的 onBindViewHolder 中 在 rootView

上设置点击监听器
holder.rootView.setOnClickListener {
   onItemClickListener?.let{
          it(currentItem)
    }
}

在你的片段中

//create the instance of UserAdapter
userAdapter.setOnItemClickListener {
  //here you have your UserModel in your fragment, do whatever you want to with it
}

还有,最后一个建议。开始使用 ViewBinding,它将使您免于繁重的工作。