This is my code for deletion
public void onBindViewHolder(#NonNull final favAdapter.ViewHolder holder, int position) {
holder.favText.setText(favlist.get(position).getPoetry());
holder.delbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DataBaseHandler db= Room.databaseBuilder(holder.delbtn.getContext(),
DataBaseHandler.class, "room_db").allowMainThreadQueries().build();
Dao_Class userDao= db.userDao();
userDao.delete(favlist.get(position));
favlist.remove(position);
notifyItemRemoved(position);
}
});
}
I tried to get adapter position but I can not get.
Instead of using position, you have to use holder.getAdapterPosition() to handle user clicks.
The ViewHolder provide us the getAdapterPosition which is always have the updated adapter’s position of this holder. It means that whenever you clicked on an item (ViewHolder item) we ask the adapter about it’s position. so you will get the latest position of this item in terms of Adapter’s logic.
You have to remove item position and notify list by applying rangeChanged method
public void onBindViewHolder(#NonNull final favAdapter.ViewHolder holder, int position) {
holder.favText.setText(favlist.get(position).getPoetry());
holder.delbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DataBaseHandler db= Room.databaseBuilder(holder.delbtn.getContext(),
DataBaseHandler.class, "room_db").allowMainThreadQueries().build();
Dao_Class userDao= db.userDao();
userDao.delete(favlist.get(position));
favlist.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, favlist.size());
}
});
}
Related
I am implementing interface to detect when view is clicked in recycler view. I am removing the item when button is clicked. It works fine when once button is clicked. But when I click second time it removes the view present next to it.
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
optionsClickEvent.onDeleteClicked(position, imagePath);
showToast(String.valueOf(position));
}
});
}
Above code is executing in onBind. Next I am removing:
#Override
public void onDeleteClicked(int position, ArrayList<String> filePath) {
filePath.remove(position);
imageAdapter.notifyItemRemoved(position);
}
This works one time perfect. But items are not updated. And when I click delete button second time the item is removed at position+1.
User holder.getAdapterPosition() instead of layout position in onClick
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
optionsClickEvent.onDeleteClicked(holder.getAdapterPosition(), imagePath);
showToast(String.valueOf(position));
}
});
}
Im trying to implement a RecyclerView in my app. This is my Adapter class:
public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems>
{
private ArrayList<CItem> items;
public AdapterItemsList(ArrayList<CItem> items)
{
this.items = items;
}
#NonNull
#Override
public ViewHolderItems onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_counter, null, false);
return new ViewHolderItems(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolderItems holder, final int position)
{
holder.asignarDatos(items.get(holder.getAdapterPosition()));
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
//deleteSelectedItem() method gonna be here
Toast.makeText(view.getContext(), String.valueOf(holder.getAdapterPosition())
, Toast.LENGTH_SHORT).show();
return false;
}
});
holder.counterAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
auxInteger += 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
});
holder.counterSubtract.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
if (auxInteger > 0)
{
auxInteger -= 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
}
});
}
#Override
public int getItemCount()
{
return items.size();
}
public class ViewHolderItems extends RecyclerView.ViewHolder
{
TextView itemName;
TextView itemNumber;
Button counterAdd;
Button counterSubtract;
public ViewHolderItems(View itemView)
{
super(itemView);
itemName = (TextView) itemView.findViewById(R.id.textViewItemCounterName);
itemNumber = (TextView) itemView.findViewById(R.id.textViewItemCounterNumber);
counterAdd = (Button) itemView.findViewById(R.id.buttonItemCounterAdd);
counterSubtract = (Button) itemView.findViewById(R.id.buttonItemCounterSubtract);
}
public void asignarDatos(CItem item)
{
itemName.setText(item.getObjectName());
itemNumber.setText(item.getObjectNumber().toString());
}
}
}
The code that "creates" the adapter:
private void CreateAdapter() {
recyclerViewItems.setAdapter(null);
items.clear();
//I dont post the code, but this just gets data from a SQLite database and populate "items".
LoadClientsList();
final AdapterItemsList adapter = new AdapterItemsList(items);
recyclerViewItems.setAdapter(adapter);
}
As you can see, I never use "implements View.OnLongClickListener" or something like that, but I just set the OnClickListener inside onBindViewHolder. Now there is a "Toast" inside (which appears just fine when I test the app), but later on, there should be my "delete item" dialog, that gonna give the user the change to Accept or Cancel (an usual dialog). If the user press "accept" then I gonna remove the item from the list.
I gonna admit, Im not an Android or Java Ninja, so I know there are horrendous mistakes probably. But the thing is, the app is working by now (the Toast appears correctlywhen I long-press an item), but the fact that I never use "implements", while I see everyone does it in StackOverflow questions related to RecyclerViews and Adapters, make me think Im making (several) serious mistakes.
I could admit since Im not a master at Java fundamentals (some years working with COBOL already that I remember almost NULL of OOP), I don't see where my mistakes are, but still, any help will be much appreciated.
Thanks in regard!
UPDATE:
Ok I was changing my code and now its like follows:
public class AdapterItemsList extends
RecyclerView.Adapter<AdapterItemsList.ViewHolderItems> implements
View.OnClickListener {
private ArrayList<CItem> items;
/* Added this */
private View.OnClickListener listener;
public AdapterItemsList(ArrayList<CItem> items)
{
this.items = items;
}
#NonNull
#Override
public ViewHolderItems onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_counter, null, false);
/* Added this */
view.setOnClickListener(this);
return new ViewHolderItems(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolderItems holder, final int position)
{
holder.asignarDatos(items.get(holder.getAdapterPosition()));
holder.counterAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
auxInteger += 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
});
holder.counterSubtract.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
if (auxInteger > 0)
{
auxInteger -= 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
}
});
}
#Override
public int getItemCount() { [...] }
/* Added this */
public void setOnClickListener(View.OnClickListener listener)
{
this.listener = listener;
}
/* Added this */
#Override
public void onClick(View view) {
if (listener != null)
{
listener.onClick(view);
}
}
public class ViewHolderItems extends RecyclerView.ViewHolder { [...] } }
Code where I create the adapter:
private void CreateAdapter() {
recyclerViewItems.setAdapter(null);
items.clear();
LoadClientsList();
final AdapterItemsList adapter = new AdapterItemsList(items);
/* Added this */
adapter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), String.valueOf(recyclerViewItems.getChildAdapterPosition(view)), Toast.LENGTH_SHORT).show();
}
});
recyclerViewItems.setAdapter(adapter);
}
The "recyclerViewItems.getChildAdapterPosition(view)" finally solves my problem (didn't mentioned before, but it was the reason why I put the "setOnClick..." inside the onBindViewHolder method, just because I needed the position of the pressed item and I couldnt figure out how on earth to access it).
So now I set the listener when I create the adapter instead of when Binding the View holder, which I guess it's better.
Still, I didnt change the "holder.counterAdd.setOnClickListener" and "holder.counterSubtract.setOnClickListener" lines, since I think they must be inside the onBindViewHolder method, but I guess Im still wrong on that.
I disagree with most of the comments on your question, and I think that the way you've written your adapter is pretty good. It's not perfect, but there is nothing wrong with manually setting a View.OnClickListener to some (or many) views inside your ViewHolder. In fact, this is the Google-recommended way of doing things!
I would make some changes, however. The first would be to move the declaration of your click listeners into the onCreateViewHolder() method (by putting them inside the ViewHolder's constructor). The second would be to add checks for NO_POSITION to make sure you handle the case where an item has been removed from your adapter but the layout hasn't been recalculated yet.
Here is what I'd recommend:
public ViewHolderItems(View itemView)
{
super(itemView);
itemName = (TextView) itemView.findViewById(R.id.textViewItemCounterName);
itemNumber = (TextView) itemView.findViewById(R.id.textViewItemCounterNumber);
counterAdd = (Button) itemView.findViewById(R.id.buttonItemCounterAdd);
counterSubtract = (Button) itemView.findViewById(R.id.buttonItemCounterSubtract);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
deleteItem();
return true;
}
});
counterAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
itemAdd();
}
});
counterSubtract.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
itemSubtract();
}
});
}
private void deleteItem() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
items.remove(position);
adapter.notifyItemRemoved(position);
}
}
private void itemAdd() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
item.setObjectNumber(item.getObjectNumber() + 1);
adapter.notifyItemChanged(position);
}
}
private void itemSubtract() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
if (item.getObjectNumber() > 0) {
item.setObjectNumber(item.getObjectNumber() - 1);
adapter.notifyItemChanged(position);
}
}
}
And then your onBindViewHolder() is extremely simple:
#Override
public void onBindViewHolder(#NonNull ViewHolderItems holder, int position)
{
holder.asignarDatos(items.get(position));
}
So, let's talk about what I'm doing here.
First, I pushed all of the listener setup into the constructor of your ViewHolder. This means that the listeners are all assigned exactly once. In order to make that still function in a world where ViewHolders are recycled and attached to different items, we have to use getAdapterPosition() to make sure that we're always interacting with the correct item in your list.
We have to check for NO_POSITION because RecyclerView layout operations are asynchronous: when you delete an item from the list, there is a gap where the item doesn't exist in your adapter any more but still is displayed on screen. In this gap, the user might tap a button! In these cases, we just ignore the user input.
I also changed how you update the values of your items, and how you display those updates. Rather than getting the text and parsing it and then re-setting it, I always go through the adapter. Remember that the goal of your RecyclerView implementation is to be able to display any element in your list correctly. The best way to do this is to update the element in your data set, and then notify the RecyclerView that that element has changed, and let onBindViewHolder() take care of the required updates.
I have recyclerview on my Fragment.When I am deleting the last item from Recyclerview it gets deleted but it is visible on Layout. I need to manually refresh the Fragment then it is gone. This happens only for deleting the last item otherwise delete the item from RecyclerView works fine.
This is code for calling Delete method using interface from AdapterClass
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name;
private TextView number;
private TextView people;
private ImageView deleteReservation;
public ViewHolder(View itemView, final OnEntryClickListener listener) {
super(itemView);
name=(TextView)itemView.findViewById(R.id.name);
number=(TextView) itemView.findViewById(R.id.number);
people=(TextView)itemView.findViewById(R.id.people);
deleteReservation=(ImageView)itemView.findViewById(R.id.delete);
editReservation=(ImageView)itemView.findViewById(R.id.editReservation);
deleteReservation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener!=null) {
int position = originalList.indexOf(filter.get(getAdapterPosition()));
if (position != RecyclerView.NO_POSITION) {
listener.deleteReservation(position);
}
}
}
});
This is code for deleting item from RecyclerView
#Override
public void deleteReservation(final int position) {
removePeople = current.get(position).getNoOfPeople();
removeId = current.get(position).getReserveid();
removeTime = current.get(position).getFullTime();
AlertDialog.Builder confirm = new AlertDialog.Builder(getActivity());
confirm.setTitle("Confirmation");
confirm.setMessage("Are you sure to cancel reservation ?");
confirm.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
removeFromReservation();
removeItem(position);
}
});
This is method to delete item.
public void removeItem(int position) {
current.remove(position);
adapter.notifyItemRemoved(position);
//adapter.notifyItemRangeChanged(position, current.size());
adapter.notifyDataSetChanged();
if(current.size()==0){
current.clear();
getData();
}
}
try this function hope it works for you
public void removeItemAt(int position) {
current.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, current.size());
}
Pass ItemView along with the position parameter in order to Invisible it. I have written my connect hopefully it will work for you!
listener.deleteReservation(position,itemView);
public void deleteReservation(final int position , View itemView){
.
.
.
public void onClick(DialogInterface dialog, int which) {
removeFromReservation();
removeItem(position,itemView); // there pass again
}
}
Make ItemView invisible or Gone in this method...
public void removeItem(int position,itemView) {
current.remove(position);
adapter.notifyItemRemoved(position);
//adapter.notifyItemRangeChanged(position, current.size());
itemView.setVisibility(View.GONE);
adapter.notifyDataSetChanged();
if(current.size()==0){
current.clear();
getData();
}
}
When I click item of RecyclerView and I want to be able to open another activity. How can I do this?
This code is my recycler adapter onBindViewHolder code.
#Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.setItemclickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position, boolean isLongClick) {
if(isLongClick){
Toast.makeText(context,"Long Click"+ dataset.get(position),Toast.LENGTH_SHORT).show();
}
else{
Intent intent=new Intent(context,MainActivity.class);
startActivity(intent);
Toast.makeText(context,"short Click"+ dataset.get(position),Toast.LENGTH_SHORT).show();
}
}`enter code here`
});
Groups tiklanilan=dataset.get(position);
holder.groupnametext.setText(tiklanilan.getGroupname());
//holder.groupimage.setImageResource(tiklanilan.getImageURL());
}
You should not use setItemClickListener but instead in your onBindViewHolder add a clickListener on your root view and call the method startActivity in that clickListener.
#Override
public void onBindViewHolder(AccountListViewHolder holder, int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.getContext().startActivity(yourIntent);
}
});
}
i have recyclerview and button on the all item of list. when i click the button in my adapter item deleted and i want refresh recycler and show new data.
#Override
public void onBindViewHolder(final LietnerViewHolder holder, final int position) {
lietner = lietners.get(position);
holder.txt_en.setText(lietner.getText_en());
holder.txt_pe.setText(lietner.getText_pe());
holder.time.setText(lietner.getTime());
holder.data.setText(HelperCalendar.g2j(lietner.getTime_create()));
holder.next_level.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
G.databaseOpenHelper.goToNextLevel(lietners.get(position).getId());
}
});
}
For re-initializing the recycler view and get callback on onBindViewHolder
simple call notifyDataSetChanged();
#Override
public void onBindViewHolder(final LietnerViewHolder holder, final int position) {
lietner = lietners.get(position);
holder.next_level.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// delete the item, or change the data.
notifyDataSetChanged();
}
});
}
i do this and it work for me!
#Override
public void onBindViewHolder(final LietnerViewHolder holder, final int position) {
lietner = lietners.get(position);
holder.txt_en.setText(lietner.getText_en());
holder.txt_pe.setText(lietner.getText_pe());
holder.time.setText(lietner.getTime());
holder.data.setText(HelperCalendar.g2j(lietner.getTime_create()));
holder.next_level.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
G.databaseOpenHelper.goToNextLevel(lietners.get(position).getId());
lietners.remove(position);
notifyDataSetChanged();
}
});
}