如何在Recycler View中回收视图

时间:2015-09-16 09:37:23

标签: android android-recyclerview

我正在使用Recycler视图来创建列表视图。在列表视图中,每个项目都有水平滚动条。在水平滚动条中,我根据特定的业务逻辑显示一个项目或3个项目。列出时,前两个卷轴显示我想要的内容。但是对于进一步的滚动,我在水平滚动视图中显示的项目有问题。它显示多个项目,其中只有一个项目。经过调查,我开始知道它的原因是,视图没有被回收。

搜索之后,我重写了这个函数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
        }
    }
}

活动代码

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))

1 个答案:

答案 0 :(得分:1)

我不知道你期望什么样的“回收”,但RecyclerView做的是它会调用onCreateViewHolder(),直到它有足够的视图来覆盖比屏幕上可见的更多的视图。 。 然后,它将调用onBindViewHolder()来填充创建的视图中的数据。

当您开始滚动时,它会抓取一个已创建的视图,并使用新的onBindViewHolder()将其反馈回position。它不会对视图符号进行任何魔术重置。

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