首页 > 解决方案 > 在从 API 检索和更新数据时保留可扩展 recyclerview 的布局

问题描述

我目前有一个功能齐全的可扩展RecyclerView(有两个不同的视图:一个用于标题,另一个用于每个标题的内容)。标题下每张卡片的内容是从对我的后端的 API 调用中检索的。

今天,我设法实现了滑动刷新功能,但问题是当我进行刷新时,组都崩溃了。从 UI/UX 的角度来看,这不是很吸引人,并且为用户增加了额外的步骤。因此,我正在寻找一种在不导致组崩溃的情况下执行滑动刷新的方法(即卡片的内容得到更新,但卡片保持在与调用刷新时相同的位置)。我已经在此处此处查看了此答案中的使用onSaveInstanceState和详细信息,但无济于事。onRestoreInstanceState

我的适配器代码如下:

class BusStopsServicesArrivalRVAdapter :
    RecyclerView.Adapter<RecyclerView.ViewHolder>(), BusStopNoSectionHeaderViewHolder.HeaderViewHolderCallback {
    private val SERVICE_TYPE = 1
    private val STOP_TYPE = 2
    private var busStopServiceList: ArrayList<BusStopService>? = null
    private var busStopList: ArrayList<String>? = null

    private var busArrivalViewTypes: SparseArray<BusArrivalViewType>? = null
    private var headerExpandTracker: SparseIntArray? = null

    lateinit var context: Context

    var nineOneCount = 0
    var threeOneCount = 0
    var threeNineCount = 0
    var fiveNineCount = 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val view: View
        when (viewType) {
            SERVICE_TYPE -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_service, parent, false)
                return BusStopServiceHolder(view)
            }
            STOP_TYPE -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_section, parent, false)
                return BusStopNoSectionHeaderViewHolder(view, this)
            }
            else -> {
                view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.card_bus_stop_service, parent, false)
                return BusStopServiceHolder(view)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val itemViewType = getItemViewType(position)
        val viewType = busArrivalViewTypes!!.get(position)
        if (itemViewType == SERVICE_TYPE) {
            bindBusStopServiceViewHolder(holder, viewType)
        } else {
            bindHeaderViewHolder(holder, position, viewType)
        }
    }

    private fun bindHeaderViewHolder(holder: RecyclerView.ViewHolder, position: Int, busArrivalViewType: BusArrivalViewType) {
        val dataIndex = busArrivalViewType.dataIndex
        val headerViewHolder = holder as BusStopNoSectionHeaderViewHolder
        when(busStopList!![dataIndex]) {
            "D" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_D)
            }

            "C" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_C)
            }

            "B" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_B)
            }

            "A" -> {
                headerViewHolder.busStopNoTextView.text =
                    context.resources.getString(R.string.bus_stop_services_description_A)
            }
        }
        // headerViewHolder.busStopNoTextView.text = busStopList!![dataIndex]
        if (isExpanded(position)) {
            headerViewHolder.busStopNoTextView
                .setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowUp, null)
        } else {
            headerViewHolder.busStopNoTextView
                .setCompoundDrawablesWithIntrinsicBounds(null, null, headerViewHolder.arrowDown, null)
        }
    }

    private fun bindBusStopServiceViewHolder(holder: RecyclerView.ViewHolder, busArrivalViewType: BusArrivalViewType) {
        val dataIndex = busArrivalViewType.dataIndex
        (holder as BusStopServiceHolder).bindData(busStopServiceList!![dataIndex], context)
    }

    override fun getItemCount(): Int {
        var count = 0
        if (busStopList != null && busStopServiceList != null) {
            busArrivalViewTypes!!.clear()
            var collapsedCount = 0
            for (i in busStopList!!.indices) {
                busArrivalViewTypes!!.put(count, BusArrivalViewType(i, STOP_TYPE))
                count += 1
                val userType = busStopList!![i]
                val childCount = getChildCount(userType)
                if (headerExpandTracker!!.get(i) != 0) {
                    // Expanded State
                    for (j in 0 until childCount) {
                        busArrivalViewTypes!!.put(count, BusArrivalViewType(count - (i + 1) + collapsedCount, SERVICE_TYPE))
                        count += 1
                    }
                } else {
                    // Collapsed
                    collapsedCount += childCount
                }
            }
        }
        return count
    }

    override fun getItemViewType(position: Int): Int {
        return if (busArrivalViewTypes!!.get(position).type === STOP_TYPE) {
            STOP_TYPE
        } else {
            SERVICE_TYPE
        }
    }

    private fun getChildCount(type: String): Int {
        when (type) {
            "D" -> return nineOneCount
            "C" -> return threeOneCount
            "B" -> return threeNineCount
            "A" -> return fiveNineCount
            else -> return 0
        }
    }

    fun setUserListAndType(busStopServiceList: ArrayList<BusStopService>?, busStopNoList: ArrayList<String>?, c: Context) {
        if (busStopServiceList != null && busStopNoList != null) {
            this.busStopServiceList = busStopServiceList
            this.busStopList = busStopNoList
            this.context = c
            busArrivalViewTypes = SparseArray<BusArrivalViewType>(busStopServiceList.size + busStopNoList.size)
            headerExpandTracker = SparseIntArray(busStopNoList.size)
            notifyDataSetChanged()

            for (i in busStopServiceList.indices) {
                when(busStopServiceList[i].busStopCode) {
                    "D" -> {
                        nineOneCount += 1
                    }

                    "C" -> {
                        threeOneCount += 1
                    }

                    "B" -> {
                        threeNineCount += 1
                    }

                    "A" -> {
                        fiveNineCount += 1
                    }
                }
            }


        }
    }

    override fun onHeaderClick(position: Int) {
        val viewType = busArrivalViewTypes!!.get(position)
        val dataIndex = viewType.dataIndex
        val userType = busStopList!![dataIndex]
        val childCount = getChildCount(userType)
        if (headerExpandTracker!!.get(dataIndex) == 0) {
            headerExpandTracker!!.put(dataIndex, 1)
            notifyItemRangeInserted(position + 1, childCount)
        } else {
            headerExpandTracker!!.put(dataIndex, 0)
            notifyItemRangeRemoved(position + 1, childCount)
        }
    }

    override fun isExpanded(position: Int): Boolean {
        val dataIndex = busArrivalViewTypes!!.get(position).dataIndex
        return headerExpandTracker!!.get(dataIndex) == 1
    }

}

标签: androidkotlinandroid-recyclerviewrecyclerview-layout

解决方案


推荐阅读