如何在Recyclerview中使用recyclerview

how to recycle view in Recycler View

我正在使用 Recycler 视图创建列表视图。在列表视图中,每个项目都有水平滚动条。在水平滚动条中,我根据特定的业务逻辑显示一项或三项。列出后,前 2 个卷轴显示的正是我想要的。但是对于进一步的滚动,我在水平滚动视图中显示的项目有问题。它显示多个项目,其中只有一个项目应该在那里。查了一下才知道是因为view没有被回收

经过搜索,我重写了这个函数,onViewRecycled。这个函数在问题开始时被调用(第三个和更多的卷轴)。我不知道如何解决这个问题。我在开始时将历史列表传递给适配器。

请帮我解决这个问题。

public class HistoryAdapter(users:List<HistoryItem>): RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {

    val TAG = "HistoryAdapter"

    var historyList:List<HistoryItem>? =null
    var context: Context? =null

    init {
        historyList = users

    }

    override fun onViewRecycled(holder: ViewHolder?) {
        super.onViewRecycled(holder)
        Log.d(TAG,"********************************************************************************************************************************Views are recycled****************************")

        if (holder is HistoryAdapter.ViewHolder) {

            val handler = Handler()
            handler.post(Runnable { () -> notifyItemRemoved(holder.getOldPosition()) })
            //notifyItemRangeChanged(holder.getAdapterPosition(),historyList!!.size())
        }

    }

    override fun getItemId(position: Int): Long {
        return super.getItemId(position)
    }

    override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
        var lung: Boolean? = false
        var tag: String? = null
        val historyItem: HistoryItem = historyList!!.get(position)

        holder!!.profileImg.setImageBitmap(BitmapFactory.decodeFile(File(Environment.getDataDirectory().getAbsolutePath(), "data/" + context!!.getPackageName() + "/files/users/" + historyItem.uuidVal + "/portrait.png").getAbsolutePath()))

        holder!!.notesTxt.setText(historyItem.sessionVal!!.getNote())

        val date = historyItem.sessionVal!!.getDate()
        var formatDayOfMonth  = SimpleDateFormat("dd");
        val day = Integer.parseInt(formatDayOfMonth.format(date));
        val dayStr = day.toString();

        formatDayOfMonth  = SimpleDateFormat("MMM")
        val month = formatDayOfMonth.format(date)

        formatDayOfMonth = SimpleDateFormat("yyyy")
        val year = formatDayOfMonth.format(date)

        formatDayOfMonth = SimpleDateFormat("hh:mm a")
        val currentTime = formatDayOfMonth.format(date)


        val dateStr = month+" "+dayStr+", "+year

        holder!!.dateTxt.setText(dateStr)
        holder!!.timeTxt.setText(currentTime)

        Log.d(TAG,"********************************************************************************************************************************************user =>"+historyItem.uuidVal);
        Log.d(TAG,"********************************************************************************************************************************************current time =>"+currentTime);

        var ambientTemp: Double? = null
        var surfaceTemp: Double? = null
        var coreBodyTemp: Double? = null

        var heartRate: Int? = null
        var lungAvailable: Boolean = false
        var heartAvailable: Boolean = false
        var tempAvailable: Boolean = false

        try {
            val tempRecording:TemperatureRecording = checkNotNull(historyItem.sessionVal!!.getTemperature())
            tempAvailable = true
            ambientTemp = tempRecording.getAmbientTemp()
            surfaceTemp = tempRecording.getSurfaceTemp()
            coreBodyTemp = TemperatureRecording.CalculateCoreBodyTemperature.getCoreBodyTemp(ambientTemp,surfaceTemp)
        } catch(i: IllegalStateException) {
            Log.w(TAG,"Temperature not available for user session")
            tempAvailable = false
        }

        try {
            val heartRecording:HeartRecording = checkNotNull(historyItem.sessionVal!!.getHeart())
            heartAvailable = true
            heartRate = heartRecording.getHeartRate()
        } catch(i: IllegalStateException) {
            Log.w(TAG,"Heart not available for user session")
            heartAvailable = false
        }

        try {
            val lungRecording:LungsRecording = checkNotNull(historyItem.sessionVal!!.getLungs())
            lungAvailable = true
        } catch(i: IllegalStateException) {
            Log.w(TAG,"Lung not available for user session")
            lungAvailable = false
        }



        Log.d(TAG,"********************************************************************************************************************************************temperature =>"+tempAvailable)
        Log.d(TAG,"********************************************************************************************************************************************heart =>"+heartAvailable)
        Log.d(TAG,"********************************************************************************************************************************************lung =>"+lungAvailable)

        //Log.d(TAG,"********************************************************************************************************************************************ambient temp val =>"+ambientTemp)
        //Log.d(TAG,"********************************************************************************************************************************************surface temp val =>"+surfaceTemp)
        //Log.d(TAG,"********************************************************************************************************************************************heart val =>"+heartRate)
        //Log.d(TAG,"********************************************************************************************************************************************lung val =>"+historyItem.sessionVal!!.getLungs())

        val parentLinearLayout = holder!!.readingsView
        //createLayout(holder!!.readingsView,tag,coreBodyTemp,heartRate)
        var childLinearLayout: LinearLayout? = null

        if(tempAvailable == true && heartAvailable == true && lungAvailable == true) {
            for(i in 1..3) {
                if(i == 1) {
                    val df = DecimalFormat("#.##");
                    childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
                    parentLinearLayout.addView(childLinearLayout)
                    childLinearLayout = null
                } else if(i == 2) {
                    childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
                    parentLinearLayout.addView(childLinearLayout)
                    childLinearLayout = null
                } else if(i == 3) {
                    childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
                    parentLinearLayout.addView(childLinearLayout)
                    childLinearLayout = null
                }
            }
        } else if (tempAvailable) {
            val df = DecimalFormat("#.##");
            childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
            parentLinearLayout.addView(childLinearLayout)
            childLinearLayout = null
        } else if (heartAvailable) {
            childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
            parentLinearLayout.addView(childLinearLayout)
            childLinearLayout = null
        } else if (lungAvailable) {
            childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
            parentLinearLayout.addView(childLinearLayout)
            childLinearLayout = null
        }



    }

    fun createChildView(icon: Bitmap,readingVal: String, readingTag: String) : LinearLayout {
        val lp = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
        lp.weight = 1f
        val parent: LinearLayout = LinearLayout(context!!)
        parent.setOrientation(LinearLayout.HORIZONTAL)
        parent.setLayoutParams(lp)

        val imageView = ImageView(context!!)
        val layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
        layoutParams.weight = 0.4f
        layoutParams.leftMargin = 10
        layoutParams.rightMargin = 10
        layoutParams.topMargin = 10
        layoutParams.bottomMargin =10

        imageView.setLayoutParams(layoutParams)
        imageView.setImageBitmap(icon)
        parent.addView(imageView)


        val readingLayout = LinearLayout(context!!)
        readingLayout.setOrientation(LinearLayout.VERTICAL)
        val lp1 = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
        lp1.weight = 0.6f
        lp1.topMargin = 10
        readingLayout.setLayoutParams(lp)

        val displayValue = TextView(context!!)
        val layoutParams1 = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 0)
        layoutParams1.weight = 0.7f
        displayValue.setLayoutParams(layoutParams1)
        displayValue.setText(readingVal)
        readingLayout.addView(displayValue)

        val displayTag = TextView(context!!)
        layoutParams1.weight = 0.3f
        displayTag.setLayoutParams(layoutParams1)
        displayTag.setText(readingTag)
        readingLayout.addView(displayTag)


        parent.addView(readingLayout)

        return parent


    }

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder? {
        context = parent!!.getContext()
        // create a new view
        val v: View = LayoutInflater.from(parent!!.getContext())
                .inflate(R.layout.layout_history_row, parent, false);

        return ViewHolder(v)
    }

    override fun getItemCount(): Int {
        return historyList!!.size()

    }

    public class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        public var profileImg: ImageView
        public var dateTxt: TextView
        public var timeTxt: TextView
        public var locationTxt: TextView
        public var notesTxt: TextView
        //public var icon: ImageView
        //public var readingTxt: TextView
        //public var readingDescTxt: TextView

        public var readingsView: LinearLayout


        init {
            profileImg = itemView.findViewById(R.id.profileImage) as ImageView
            dateTxt = itemView.findViewById(R.id.date) as TextView
            timeTxt = itemView.findViewById(R.id.time) as TextView
            locationTxt = itemView.findViewById(R.id.location) as TextView
            notesTxt = itemView.findViewById(R.id.notes) as TextView
            //readingTxt = itemView.findViewById(R.id.readings) as TextView
            //readingDescTxt = itemView.findViewById(R.id.readingsDesc) as TextView
//            icon = itemView.findViewById(R.id.icon) as ImageView
            readingsView = itemView.findViewById(R.id.readingsView) as LinearLayout
        }
    }
}

Activity代码

val history = findViewById(R.id.history) as RecyclerView
for(user in allUsers) {
            val uuid: String? = user.getId()
            Log.d(TAG,"*****************************************************************************************************************UUID=>"+uuid+"FirstName=>"+user.getFirstName()+",sessions size =>"+user.getSessions().size())
            for(session in user.getSessions()) {
                historyItems.add(HistoryItem(user.getId(),session))
            }
        }

history.setHasFixedSize(true);
        history.setAdapter(HistoryAdapter(historyItems))
        history.setLayoutManager(LinearLayoutManager(this))

我不知道你期待什么样的 "recycling",但 RecyclerView 所做的是它会调用 onCreateViewHolder() 直到它有足够的 viewholders 来覆盖比实际内容略多的内容在屏幕上可见。 然后它将调用 onBindViewHolder() 来填充创建的视图持有者中的数据。

当您开始滚动时,它会抓取一个已创建的视窗,并使用新的 position 将其反馈到 onBindViewHolder()。它不会对取景器进行任何神奇的重置。

在您的情况下,您永远不会重置 readingsView,因此适配器不断向其添加子项(这就是为什么当您进一步滚动浏览数据时它包含的子项比预期的多)。在 onBindViewHolder() 中,您需要先从 readingsView 中删除所有现有子项,然后再开始添加新子项。