I am working on a project which implements 2 views for each screen, a normal user view, and an admin view. The admin view is presented with a little more privileges than a normal user like deleting certain posts or the users themselves from the database.
Therefore, I set the visibility of those functional buttons to be GONE
if the admin privilege is true (which I pass as a parameter value when initializing the adapter). But what I am struggling with, is where do I set the visibility, in the onCreateViewHolder
method or onBindViewHolder
method? I have right now set it in the onCreateViewHolder method because I had read on some Stackoverflow answer only that we should avoid heavy operations in onBindViewHolder method. But I would like to know a definitive answer.
Here are the code samples for reference:
The adapter class declaration:
class NoticesAdapter(options: FirestoreRecyclerOptions<NoticeModel>,
private val isAdmin: Boolean,
private val listener: INoticeListAdapter):
FirestoreRecyclerAdapter<NoticeModel, NoticesAdapter.NoticeViewHolder>(options)
onCreateViewHolder meothod:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoticeViewHolder {
val noticeListView = LayoutInflater.from(parent.context).inflate(R.layout.item_notice, parent, false)
val noticeListViewHolder = NoticeViewHolder(noticeListView)
if (!isAdmin)
{
noticeListViewHolder.deleteNoticeBtn.visibility = GONE
}
// On clicking the delete button on a notice by the admin
noticeListViewHolder.deleteNoticeBtn.setOnClickListener {
val noticeSnapshot = snapshots.getSnapshot(noticeListViewHolder.adapterPosition)
listener.deleteNoticeBtnListener(noticeSnapshot)
}
return noticeListViewHolder
}
The onBindViewHolder method:
override fun onBindViewHolder(holder: NoticeViewHolder, position: Int, model: NoticeModel) {
holder.noticeText.text = model.noticeText
holder.noticeAuthor.text = MyUtils.getUserName()
holder.noticePostDate.text = model.datePosted
holder.noticePostTime.text = model.timePosted
}
A RecyclerView.Adapter
what it does is to: recycle items (as the name implies). The list doesn't have one view per item on the data source at the same time. The adapter makes sure to have enough views in memory in order to always render the list smoothly. When a row is leaving the field of view by scrolling, then that view is recycled to be re-used in the next entering view to the screen size.
This means that onCreateViewHolder
is called only when a view is needed to be created. Generally at the start of the adapter, also when the user is scrolling fast or erratically and when the data set changes and is needed.
The other method onBindViewHolder
is called every time the data on the row needs to be updated in order for the view to get updated. This is called every time a row is entering the view field of the screen.
So the textbook answer is: do it on onBindViewHodlder
, because if the attribute isAdmin
changes then that row will need to be updated. By doing it on onCreateViewHolder
that would only happen one time when the row is created.
But, your isAdmin
is a val on the constructor that can not be reassigned, so this means that when the rows are created the button will be hidden or visible forever. And this doesn't matter because your structure is to determine if is admin from another source that is separated from which the row data structure is derived from.
If in some case you want to:
Then the solution is to move the isAdming
attribute to your NoticeModel
, that would imply changing your data structure.
If you want to verify anything sai above, get a data source with plenty of items and then add 2 logs, one on onCreateViewHolder
and one in onBindViewHolder
. You will see how on create is called only sometimes but on bind is called always.