简体   繁体   English

如何解决 RecyclerView.Adapter 问题?

[英]How to solve RecyclerView.Adapter issue?

I am trying to change first text(position = 0) gravity from List in 'onBindViewHolder(viewHolder: ViewHolder, position: Int)', but, except for the first, the gravity of some elements changes.我试图从'onBindViewHolder(viewHolder:ViewHolder,位置:Int)'中的List更改第一个文本(位置= 0)重力,但是,除了第一个,某些元素的重力发生了变化。 Could you tell me where this problem comes from?你能告诉我这个问题是从哪里来的吗?

You can see code below and also logs您可以在下面查看代码以及日志

class ButtonsListAdapter(private val dataSet: List<String>) :
    RecyclerView.Adapter<ButtonsListAdapter.ViewHolder>() {

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView
        val divider: View

        init {
            textView = view.findViewById(R.id.textView)
            divider = view.findViewById(R.id.divider)
        }
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(viewGroup.context)
            .inflate(R.layout.buttons_list_item, viewGroup, false)

        return ViewHolder(view)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {

        viewHolder.textView.text = dataSet[position]
        if(position == 0) {
            Log.i("Position", " position ->  $position ")
            viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
        }
        Log.i("Position", " gravity ->  $position " + viewHolder.textView.gravity)
    }

    override fun getItemCount() = dataSet.size
}

Logs日志

I/Position:  position ->  0 
I/Position:  gravity ->  0 8388627
I/Position:  gravity ->  1 17
I/Position:  gravity ->  2 17
I/Position:  gravity ->  3 17
I/Position:  gravity ->  4 17
I/Position:  gravity ->  5 17
I/Position:  gravity ->  6 17
I/Position:  gravity ->  7 17
I/Position:  gravity ->  8 17
I/Position:  gravity ->  9 8388627
I/Position:  gravity ->  10 17
I/Position:  gravity ->  11 17
I/Position:  gravity ->  12 17
I/Position:  gravity ->  13 17
I/Position:  gravity ->  14 17
I/Position:  gravity ->  15 17
I/Position:  gravity ->  16 17
I/Position:  gravity ->  17 17
I/Position:  gravity ->  9 8388627
I/Position:  gravity ->  8 17
I/Position:  gravity ->  7 17
I/Position:  gravity ->  6 17
I/Position:  gravity ->  5 17
I/Position:  gravity ->  4 17
I/Position:  gravity ->  3 17
I/Position:  gravity ->  2 17
I/Position:  gravity ->  1 17
I/Position:  position ->  0 
I/Position:  gravity ->  0 8388627

I believe the RecyclerView tries to use old rows to save on memory usage.我相信 RecyclerView 尝试使用旧行来节省内存使用量。 It's kinda like: when the view 0 goes out the screen, the new line 9 will "recycle" it to show itself (that why it's called RecyclerView).这有点像:当视图 0 出现在屏幕上时,新的第 9 行将“回收”它以显示自己(这就是它被称为 RecyclerView 的原因)。

If you want a different first line, try override the method int getItemViewType(int position) and specify that the first item is a "different type" from the rest如果您想要不同的第一行,请尝试覆盖方法int getItemViewType(int position)并指定第一个项目是与其余项目“不同的类型”

(or you could just add an else on if(position == 0) and force the gravity you want, but I think the other option is more elegant) (或者你可以在if(position == 0)上添加一个 else 并强制你想要的重力,但我认为另一个选项更优雅)

ReyclerView s have a handful of ViewHolder s that they swap around to make it look like a large list, but really it's the same few boxes riding along a conveyor belt, being moved from the end back to the start. ReyclerView有一些ViewHolder ,它们交换它们以使其看起来像一个大列表,但实际上它是沿着传送带移动的相同的几个盒子,从末端移回开始。

onBindViewHolder is where you set the contents of one of those boxes to display the item at that position in the list. onBindViewHolder是您设置其中一个框的内容以在列表中的该位置显示项目的位置。 The ViewHolder that you're provided with still looks like it did when it was set up to display a previous item, so you need to make sure everything is set up correctly for the new one.提供给您的ViewHolder看起来仍然与设置为显示前一个项目时一样,因此您需要确保为新项目正确设置了所有内容 Anything you don't change, will stick and look like the last item it was displaying.您不更改的任何内容都会在上面,看起来就像它显示的最后一个项目。

So here's your problem:所以这是你的问题:

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder.textView.text = dataSet[position]
    if(position == 0) {
        viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
    }
}

Part of the display state that changes between items is the gravity - and here you're setting it for item 0 , but you're not setting it to normal for the other items.项目之间变化的部分显示状态是重力 - 在这里您将其设置为项目 0 ,但您没有将其设置为其他项目的正常状态。 It's sticky , you only set it one way, and it can never revert.它很,你只能设置一种方式,它永远不会恢复。 So the next item that needs to display in that recycled ViewHolder object will have that same gravity setting, because that's what it's been set to!因此,需要在该回收的ViewHolder对象中显示的下一个项目将具有相同的重力设置,因为这就是它的设置! Which is item 9 going by your logs (you can see how many ViewHolder s are getting created by when the reuse starts - looks like it happens to use 9 of them in this case)哪个是您的日志中的第9 项(您可以看到在重用开始时创建了多少ViewHolder - 看起来在这种情况下碰巧使用了其中的 9 个)


So yeah, you need to set the gravity in all cases - set the whole display state for every item, to ensure it's consistent and that none of the old state can influence how it looks now:所以,是的,您需要在所有情况下设置重力 - 为每个项目设置整个显示状态,以确保它是一致的,并且旧状态都不会影响它现在的外观:

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder.textView.text = dataSet[position]
    // explicitly set the gravity every time
    if(position == 0) {
        viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
    } else {
        viewHolder.textView.gravity = // whatever
    }
}

But I hope that makes the broader point clearer - you always need to do this stuff with RecyclerView s when you're binding items, because you're reusing old items that are filled in with old data and old state.但我希望这能让更广泛的观点更清楚——当你绑定项目时,你总是需要用RecyclerView来做这些事情,因为你正在重用填充了旧数据和旧状态的旧项目。 So you should fully configure them each time, for anything that could potentially change.因此,您应该每次都完全配置它们,以应对可能发生的任何变化。 You don't want any old state hanging around!您不希望任何旧状态徘徊!

(Luiz's answer is also a good option, having a completely separate item type for a header allows you to use a different ViewHolder with its own layout etc, so there's no need to keep reconfiguring a single layout. But it might be too much work if you're making a small change - you have options!) (Luiz 的回答也是一个不错的选择,为标题提供完全独立的项目类型允许您使用具有自己布局等的不同ViewHolder ,因此无需继续重新配置单个布局。但如果你正在做一个小改变 - 你有选择!)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM