我正在尝试使用 recyclerview 在屏幕上打印列表,但适配器部分中的代码不起作用

Posted

技术标签:

【中文标题】我正在尝试使用 recyclerview 在屏幕上打印列表,但适配器部分中的代码不起作用【英文标题】:I'm trying to print a list on the screen using the recyclerview, but the code in the adapter part is not working 【发布时间】:2021-11-18 22:02:18 【问题描述】:

MainActivity 如下。 屏幕上什么都没有出现,但我不知道哪一部分是错误的。 如何添加 TV_item_name 的值?

并且在日志中,它来自内部类的 DetailViewAdapter。 Log.d(logTag,onCreateViewHolder11iscaled") 值也没有输出,请问是什么问题?

package com.example.test_recyclerview

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.test_recyclerview.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() 
    private lateinit var binding : ActivityMainBinding
    var logTag : String? = "로그 MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        
        Log.d(logTag,"111 onCreate is called")

        binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
        val adapter = DetailViewAdapter()

        Log.d(logTag,"222 onCreate is called")
        binding.mRecyclerView.adapter = adapter
    

    override fun onDestroy() 

        super.onDestroy()
        binding.mRecyclerView.adapter = null

    

    inner class DetailViewAdapter : RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() 

        private var list = ArrayList<String>()
        var logTag : String? = "로그 MainActivity"

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DetailViewAdapter.ViewHolder 
            Log.d(logTag,"onCreateViewHolder11 is called")
            list = getItemList()
            val view = LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
            return ViewHolder(view)
        


        override fun onBindViewHolder(holder: ViewHolder, position: Int) 
            Log.d(logTag,"onBindViewHolder is called")

            for (i in 1 until list.size) 
                Log.d(logTag,"onBindViewHolder is called // list[$i] =" + list[i])
                holder.tvItem.text = list[i]
            
        

        override fun getItemCount(): Int 
            return list.size
        

        private fun getItemList(): ArrayList<String> 

            for (i in 1..8) 
                list.add(i, "Item $i")
            

            return list
        

        inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) 
            val tvItem : TextView = view.findViewById(R.id.tv_item_name)
            val cardViewItem : CardView = view.findViewById(R.id.card_view_item)
        
    

item_custom_row.xml

<?xml version="1.0" encoding="utf-8"?>
`enter code here`<LinearLayout 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:layout_
    android:layout_>


    <androidx.cardview.widget.CardView
        android:id="@+id/card_view_item"
        android:layout_
        android:layout_
        android:layout_margin="5dp"
        android:padding="10dp"
        app:cardCornerRadius="5dp"
        app:cardElevation="3dp">

        <LinearLayout
            android:layout_
            android:layout_
            android:gravity="center"
            android:orientation="horizontal"
            tools:ignore="UseCompoundDrawables">

            <ImageView
                android:layout_
                android:layout_
                android:contentDescription="@string/app_name"
                android:src="@mipmap/ic_launcher" />

            <TextView
                android:id="@+id/tv_item_name"
                android:layout_
                android:layout_
                android:layout_margin="10dp"
                android:textColor="@android:color/black"
                android:textSize="18sp"
                android:textStyle="bold"
                tools:text="Item" />
        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_
    android:layout_
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/m_RecyclerView"
        android:layout_
        android:layout_
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

【问题讨论】:

您似乎正在使用数据绑定或视图绑定,但您的视图未包含在 标记中。我很好奇您的 -Binding 类是如何生成的 viewBinding 不需要布局换行。只有数据绑定需要 我不在乎匆忙制作示例代码并用布局包装它。感谢您提供 viewBinding 不需要布局包装的信息。 【参考方案1】:

问题是您在 onCreateViewHolder 中分配列表,但由于您的 list.size 返回 0,因此不会调用它。

在answer中正确指出

    在适配器外部创建列表并从构造函数传递它 onBindViewHolder 中的更改实现

以下是您的用例的完整示例:

class MainActivity : AppCompatActivity() 

    private lateinit var binding: ActivityMainBinding
    var logTag: String? = "로그 MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        Log.d(logTag, "111 onCreate is called")

        binding.mRecyclerView.layoutManager = LinearLayoutManager(this)
        val adapter = DetailViewAdapter(getItemList())

        Log.d(logTag, "222 onCreate is called")
        binding.mRecyclerView.adapter = adapter
    

    private fun getItemList(): ArrayList<String> 
        val list = ArrayList<String>()
        for (i in 1..8) 
            list.add("Item $i")
        

        return list
    


    override fun onDestroy() 

        super.onDestroy()
        binding.mRecyclerView.adapter = null

    

    inner class DetailViewAdapter(private val list: ArrayList<String>) :
        RecyclerView.Adapter<DetailViewAdapter.ViewHolder>() 

        var logTag: String? = "로그 MainActivity"

        override fun onCreateViewHolder(
            parent: ViewGroup,
            viewType: Int
        ): DetailViewAdapter.ViewHolder 
            Log.d(logTag, "onCreateViewHolder11 is called")
            val view =
                LayoutInflater.from(parent.context).inflate(R.layout.item_custom_row, parent, false)
            return ViewHolder(view)
        


        override fun onBindViewHolder(holder: ViewHolder, position: Int) 
            Log.d(logTag, "onBindViewHolder is called")
            holder.tvItem.text = list[position]
        

        override fun getItemCount(): Int 
            return list.size
        


        inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) 
            val tvItem: TextView = view.findViewById(R.id.tv_item_name)
            val cardViewItem: CardView = view.findViewById(R.id.card_view_item)
        
    

 

【讨论】:

我学会了如何解决问题。答案很有帮助。谢谢你的好意。我还有一个问题。 view.findViewById(R.id.tv_item_name) 可以改成视图绑定吗? @happynewmind 是的,你可以。您只需要将视图持有者行更改为:ViewHolder(rowBinding: ItemCustomRowBinding) : RecyclerView.ViewHolder(rowBinding.root)onCreateViewHolder,您将其更改为return ViewHolder(ItemCustomRowBinding.bind(view)),之后您应该可以访问您的视图。 非常感谢。你提到的事情执行得很好。【参考方案2】:

从您发布的代码中,我可以看出您的代码存在两个问题。

第一个是您试图从视图持有者内部填充数据列表。会发生以下情况:

    适配器已创建 适配器想知道它应该创建多少个视图持有者来查看如何填充回收器视图。 适配器调用 getItemCount 并且此方法返回 0,因为列表尚未填充。 没有其他任何东西被调用,因为没有其他东西必须被执行。

所以,要解决这个问题,最简单的方法是让 getItemCount 返回 8 并设置好。但是,解决此问题的更好方法是在适配器之外实例化您的列表,例如在您的活动中,并在初始化适配器时将其作为构造函数参数传递。

我看到的第二个问题是 onBindViewHolder 方法。您正在遍历列表以设置文本,这将导致对于所有项目,您只会将文本设置为最后一项(第 8 项)。您需要记住 onBindViewHolder 是一个在视图持有者需要刷新其内容时调用的方法,因为它将用于显示列表的不同项目,这就是为什么此方法将位置作为参数传递,所以您可以做类似的事情:

holder.tvItem.text = list[position]

** 作为第二个问题的附注,我见过并用来渲染视图持有者内容的更通用方法是创建一个名为“bind”的公共方法,该方法将需要的项目传递给被渲染并在视图持有者上,您将了解如何绘制它的逻辑。比如:

override fun onBindViewHolder(holder: ViewHolder, position: Int) 
    holder.bind(list[position])


/// Inside the view holder

fun bind(item: String) 
    tvItem.text = item

【讨论】:

我学会了如何解决问题。答案很有帮助。谢谢你的好意。

以上是关于我正在尝试使用 recyclerview 在屏幕上打印列表,但适配器部分中的代码不起作用的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView未正确显示消息列表

浮动操作按钮未显示在 recyclerview 上(位于 DrawerLayout 内)

RecyclerView 水平滚动对齐在中心

如何获得 Recyclerview 项目中所有 Edittext 的总和?仅获取屏幕上可见的项目,而不是全部

从 Fragment 中的适配器(recyclerview)获取所有项目

如何在屏幕上设置两个相同大小的RecyclerView,保持高度换行内容以避免空白