【问题标题】:How to get data from RecyclerView adapter into the fragment after clicking on it?点击后如何从 RecyclerView 适配器获取数据到 Fragment 中?
【发布时间】:2022-09-28 22:02:06
【问题描述】:

单击该数据后,我试图将数据从 RecyclerView 适配器获取到片段中。 我尝试使用界面解决这个问题。但是我的应用程序在点击后崩溃了。

这是适配器的代码:-

class SearchPlaceAdapter(
    private var mContext: Context,
    private var mPlaces: List<String>,
    private var isFragment: Boolean = false,
): RecyclerView.Adapter<SearchPlaceAdapter.ViewHolder>(){
    private val onPlaceClickListener: MainActivity.OnPlaceClickListener? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =
            LayoutInflater.from(mContext).inflate(R.layout.rv_search_place, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val place = mPlaces[position]

        holder.place.text = place

        holder.place.setOnClickListener {
            onPlaceClickListener!!.onPlaceClick(place)
        }
    }

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

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var place: TextView =itemView.findViewById(R.id.searchPlaceTV)
    }

}

这是 MainActivity 代码:-

interface OnPlaceClickListener {
    fun onPlaceClick(place: String?)
}

这是我获取数据的片段代码:-

 override fun onPlaceClick(place: String?) {
        newPlace.text = place
    }

我认为这是一个错误。错误在适配器中:-

java.lang.NullPointerException
    at com.ehie.recyclerview.adapter.SearchPlaceAdapter.onBindViewHolder$lambda-0(SearchPlaceAdapter.kt:31)
    at com.ehi.recyclerview.adapter.SearchPlaceAdapter.$r8$lambda$KIVoR28fNIxsomM1sHTPNEhSuXQ(Unknown Source:0)
    at com.ehie.recyclerview.adapter.SearchPlaceAdapter$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
at android.view.View.performClick(View.java:7792)
        at android.widget.TextView.performClick(TextView.java:16112)
        at android.view.View.performClickInternal(View.java:7769)
        at android.view.View.access$3800(View.java:910)
        at android.view.View$PerformClick.run(View.java:30218)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at android.app.ActivityThread.main(ActivityThread.java:8751)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
  • 旁注,与您的问题无关。 m 前缀是匈牙利符号,表示变量何时是余烬变量。 Kotlin 没有成员变量,但我想同样的概念可以用于属性。但是如果你要使用它,你需要保持一致并将它用于全部属性,否则只会使您的代码更加混乱,因为您永远无法信任该表示法。 Java 和 Kotlin 程序员普遍认为应该避免使用匈牙利符号。它降低了代码的可读性,并且对于 IDE 颜色编码来说是多余的。

标签: android kotlin android-recyclerview


【解决方案1】:

问题是你没有在适配器的任何地方初始化你的onPlaceClickListener,这就是为什么当你做onPlaceClickListener!!.onPlaceClick(place)时它会抛出NullPointerException。您应该将其作为参数传递给适配器。

class SearchPlaceAdapter(
    private val onPlaceClickListener: OnPlaceClickListener,
    private val mPlaces: List<String>,
    private val isFragment: Boolean = false,
): RecyclerView.Adapter<SearchPlaceAdapter.ViewHolder>() {

从片段创建适配器时,您可以将this 传递给onPlaceClickListener 参数(它会起作用,因为您的片段实现了OnPlaceClickListener 接口)。

此外,您不需要将mContext 传递给适配器。在onCreateViewHolder 中,您可以使用parent.context 代替mContext

将数据从适配器发送到片段的另一种方法是使用 lambda 函数而不是接口。

class SearchPlaceAdapter(
    private val mPlaces: List<String>,
    private val isFragment: Boolean = false,
    private val onPlaceClick: (String?) -> Unit,
): RecyclerView.Adapter<SearchPlaceAdapter.ViewHolder>() {

    ...
    holder.place.setOnClickListener {
        onPlaceClick(place)
    }
    ...
}

// And in your fragment
val adapter = SearchPlaceAdapter(mPlaces = <yourList>) { place ->
    newPlace.text = place
}

这种方法比使用接口要简洁得多。

【讨论】:

    【解决方案2】:

    我要说你忘了设置你的onPlaceClickListener 属性,你做了,还把它标记为private,使它无法设置。

    然后你使用!!. 来调用它。 !! 的意思是“如果我碰巧在这个属性中放了一个空值,应用程序就会崩溃”。你应该(几乎)永远不要使用!!。在这种情况下,使用空安全的?. 调用是有意义的,如果onPlaceClickListener 未设置,它不会默默地执行任何操作。

    但是你需要将onPlaceClickListener设为public(去掉前面的private关键字)并在Activity或Fragment中设置它的值。或者,您可以将其移动到您的构造函数中以要求它。

    您应该将您的界面标记为fun interface 以使其更易于使用。它将允许您使用 lambda 定义它(样板更少)。

    另外,在我看来,最好不要让你的 Fragment 直接实现监听器。将侦听器定义为单独的类实例更简洁(更好的封装),例如:

    // In fragment:
    
    mySearchPlaceAdapter.onPlaceClickListener = MainActivity.OnPlaceClickListener { place ->
        newPlace.text = place
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 2016-10-03
      • 1970-01-01
      • 2013-08-27
      • 2018-12-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      相关资源
      最近更新 更多