Reputation: 2699
I would like to make generic adapter which let me reuse it. That's why I decided to not to create view by inflating
, but pass custom, previously created view to ViewHolder
in ListAdapter
(RecyclerView
) in onCreateViewHolder
. According to its documentation it should be possible, because it says:
You can either create a new View manually or inflate it from an XML layout file.
This is my adapter implementation:
class BaseAdapter<T, V : View>(
private val adapterConfig: AdapterConfig<T, V>,
private val onClick: (T) -> (Unit)
) : ListAdapter<T, BaseViewHolder<V>>(adapterConfig.diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<V> {
return adapterConfig.viewHolder.apply {
itemView.setOnClickListener { onClick(getItem(adapterPosition)) }
}
}
override fun onBindViewHolder(holder: BaseViewHolder<V>, position: Int) {
adapterConfig.bind(getItem(position), holder, position)
}
}
AdapterConfig
implementation class is reposnible for creating ViewHolder
and it's looks like this:
override val viewHolder: BaseViewHolder<ScorerView> = BaseViewHolder(ScorerView(context))
BaseViewHolder
class:
class BaseViewHolder<out V : View>(val v: V) : RecyclerView.ViewHolder(v)
(Nothing interesting until now)
My ScorerView
is:
class ScorerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.item_ranking, this, false)
}
fun configure(id: String, player: String, team: String, matchSet: String, points: String, pointsAvg: String) {
idTextView.text = id
playerTextView.text = player
teamTextView.text = team
matchSetTextView.text = matchSet
pointsTextView.text = points
pointsAvgTextView.text = pointsAvg
}
}
The problem is that when I pass false
to inflate
function (which is ok, because RecyclerView
require to item view wasn't attached to root view) then my widget instances (idTextView
for example) is null. Otherwise when I manually attach view to root either by passing true
or by calling addView(view)
I'm getting a crash saying that view can't be attached when created:
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
My question is: is it even possible? If not, why official documentation saying that it's possible to manually create view?
Upvotes: 7
Views: 2842
Reputation: 54214
The problem is that you're returning the same view over and over again. It is an explicit requirement that onCreateViewHolder()
creates a new view every time it is invoked.
The documentation says that you can create the View manually, but that still means that you manually create a different view each time onCreateViewHolder()
runs.
So, because you're re-using the same view every time, the second time your app calls onCreateViewHolder()
, the view is already attached to the parent.
Upvotes: 8