Reputation: 88
I want to be able to add items to my ReclycerView dynamically.
When an item loads -> setText() -> I add another item on list.
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final Message message = mDataset.get(position);
if(message.isAnswers()) {
holder.mAnswer1Button.setText(message.getAnswer1());
holder.mAnswer2Button.setText(message.getAnswer2());
holder.mAnswer1Button.setOnClickListener(v -> {
if(message.getChild1() > 0) {
add(position + 1, dataListShared.get(message.getChild1()));
holder.mAnswer1Button.setClickable(false);
holder.mAnswer2Button.setEnabled(false);
}
});
} else {
holder.mMessageTextView.setText(message.getMessage());
if(message.getChild1() > 0) {
add(position + 1, dataListShared.get(message.getChild1()));
holder.mMessageTextView.setEnabled(false);
}
}
}
This is what I have inside onBindViewHolder
. When I am on the first case if()
, and I click the button, the item is added to the list. On the second Case else()
, I would like for the text to be set on this current item and than already add another one.
How can I achieve this?
Moreover, why add()
works inside onClickListener but not outside of it?
The error I get is:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
Thanks! :)
Upvotes: 2
Views: 5813
Reputation: 3310
The error itself is self explanatory ... It is dangerous to setOnClickListener
in onBindViewHolder
. This method is step of refresh each recycler item.
You should move method setOnClickListener
to ViewHolder
which is inner class on your adapter.
class MyViewHolder extends RecyclerView.ViewHolder
{
private final OnClickListener mOnClickListener = new MyOnClickListener();
Button mAnswer1Button, mAnswer2Button;
public MyViewHolder (View itemView) {
super(itemView);
mAnswer1Button = (Button) itemView.findViewById(R.id.item);
mAnswer2Button = (Button) itemView.findViewById(R.id.item);
mAnswer1Button.setOnClickListener(mOnClickListener);
}
@Override
public void onClick(final View view) {
//Now your Logic ....
}
}
One more thing you could do is set Create an interface OnItemClickListener
and declare onItemClick
and then make the activity from where you are setting up the adapter for the particular recycler view implment OnItemClickListener
this and over there you can dynamically add another item and setAdapter
again or notifyDataSetChanged()
Your InterFace
public interface OnItemClickListener{
public void onItemClick(int position);
}
Your MainActivity
class MainActivity implements OnItemClickListener{
RecyclerView mRecyclerView ;
@Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.layout);
mRecyclerView = (RecyclerView ) findViewById(R.id.recyclerview);
mAdapter= new MyAdapter(ArrayList, getContext(), MainActivity.this);
}
@Overrride
public void onItemClick(int position)
{
//Now your Logic ....
}
}
Now you can call this method onItemClick
from the Adpater
clas by setting onClickListener
mAnswer1Button in the ViewHolder
class and calling this method with in the onClick
Upvotes: 1
Reputation: 394
As commented, I think it should work like this:
private int position;
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
this.position = position;
}
@Override
public void onViewAttachedToWindow(ViewHolder holder) {
final Message message = mDataset.get(position);
if(message.isAnswers()) {
holder.mAnswer1Button.setText(message.getAnswer1());
holder.mAnswer2Button.setText(message.getAnswer2());
holder.mAnswer1Button.setOnClickListener(v -> {
if(message.getChild1() > 0) {
add(position + 1, dataListShared.get(message.getChild1()));
holder.mAnswer1Button.setClickable(false);
holder.mAnswer2Button.setEnabled(false);
}
});
} else {
holder.mMessageTextView.setText(message.getMessage());
if(message.getChild1() > 0) {
add(position + 1, dataListShared.get(message.getChild1()));
holder.mMessageTextView.setEnabled(false);
}
}
}
In onBindViewHolder(), you apparently cannot change the dataset - I guess as the framework is still busy displaying the previous dataset. But when saving the position in an instance variable, and updating the dataset in onViewAttachedToWindow(), the RecylerView should be ready for more data.
To be honest though, I wouldn't add all this logic to the ViewHolder, but pass an interface to it so the logic can be kept in a more central place, like a presenter.
Upvotes: 0