I have an app that showing the item that user have from Firebase Realtime Database to Android Studio RecycleView. For each item in the RecycleView, i've added a function for user to delete the item they want to remove.
Im using fridgeRef.child(getRef(position).getKey()).removeValue();
to delete the value. My JSON structure in Firebase is
{
"Ingredient": {
"hgO9joLhmfh4Wjn7xYpyqcYmNOB3": {
"Cashews": {
"Expiry": "2023-01-21",
"Ingredient": 1
},
"Macadamia Nuts": {
"Expiry": "2022-11-22",
"Ingredient": 1
},
"Pecans": {
"Expiry": "2023-01-21",
"Ingredient": 1
},
"Pine Nuts": {
"Expiry": "2022-11-22",
"Ingredient": 1
},
"Pistachios": {
"Expiry": "2023-01-21",
"Ingredient": 1
}
}
}
}
The problem here, went i try to remove value the first value which is Cashew, it'll delete successfully, but went i try to delete Macadamia Nuts, it'll the data under it which is Pecans. The problem continue until Macadamia nuts left and went i try to delete it it'll show this error and the app will forced stop
java.lang.IndexOutOfBoundsException: Index: 4, Size: 3 at java.util.ArrayList.get(ArrayList.java:437) at com.firebase.ui.common.BaseObservableSnapshotArray.getSnapshot(BaseObservableSnapshotArray.java:70) at com.firebase.ui.database.FirebaseRecyclerAdapter.getRef(FirebaseRecyclerAdapter.java:114) at com.example.recipely.fridge$2.lambda$onBindViewHolder$0$com-example-recipely-fridge$2(fridge.java:163) at com.example.recipely.fridge$2$$ExternalSyntheticLambda0.onClick(Unknown Source:4)
fridge.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
ingredientView = inflater.inflate(R.layout.fragment_fridge, container, false);
expiryNote = (LinearLayout) ingredientView.findViewById(R.id.expiryNote);
HaveData = (ScrollView) ingredientView.findViewById(R.id.HaveData);
noFridge = (LinearLayout) ingredientView.findViewById(R.id.noFridge);
expiryNote.setVisibility(View.GONE);
HaveData.setVisibility(View.GONE);
myIngredientList = (RecyclerView) ingredientView.findViewById(R.id.ingredientList);
myIngredientList.setLayoutManager(new LinearLayoutManager(getContext()));
mAuth = FirebaseAuth.getInstance();
currentUserID = mAuth.getCurrentUser().getUid();
fridgeRef = FirebaseDatabase.getInstance().getReference().child("Ingredient").child(currentUserID);
fridgeRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
HaveData.setVisibility(View.VISIBLE);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
return ingredientView;
}
@Override
public void onStart() {
super.onStart();
FirebaseRecyclerOptions<fridgeItem> options =
new FirebaseRecyclerOptions.Builder<fridgeItem>()
.setQuery(fridgeRef , fridgeItem.class)
.build();
FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder> adapter
= new FirebaseRecyclerAdapter<fridgeItem, fridgeViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull fridgeViewHolder holder, int position, @NonNull fridgeItem model) {
String itemName = getRef(position).getKey();
LocalDate expiry = LocalDate.parse(model.getExpiry());
LocalDate today = LocalDate.now();
long dayDiff = DAYS.between(today, expiry);
if(dayDiff <= 7){
holder.cardViewIngredient.setBackgroundColor(Color.parseColor("#FFD1D1"));
expiryNote.setVisibility(View.VISIBLE);
}
holder.ingredName.setText(itemName);
holder.ingredExpiry.setText(dayDiff " Days until expiry");
holder.deleteBtn.setOnClickListener(v ->{
String output = fridgeRef.child(getRef(position).getKey()).toString();
Log.d("Fridge" , output );
fridgeRef.child(getRef(position).getKey()).removeValue();
});
}
@NonNull
@Override
public fridgeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ingredientrecycle, parent, false);
fridgeViewHolder viewHolder = new fridgeViewHolder(view);
return viewHolder;
}
};
myIngredientList.setAdapter(adapter);
adapter.startListening();
}
public static class fridgeViewHolder extends RecyclerView.ViewHolder{
TextView ingredName, ingredExpiry;
LinearLayout deleteBtn, cardViewIngredient;
public fridgeViewHolder(@NonNull View itemView) {
super(itemView);
ingredName = itemView.findViewById(R.id.itemName);
ingredExpiry = itemView.findViewById(R.id.itemExpiry);
cardViewIngredient = itemView.findViewById(R.id.cardViewIngredient);
//set button to delete an item
deleteBtn = itemView.findViewById(R.id.deleteItem);
}
}
}
CodePudding user response:
The problem that you are using old positions with the delete function, for example in the beginning Pistachios
is at position 4 but if you delete the other item it will became at position 0, that's why you get the error, the problem is on onBindViewHolder
:
@Override
protected void onBindViewHolder(@NonNull fridgeViewHolder holder, int position, @NonNull fridgeItem model) {
// the correct itemName is going to be stored here
String itemName = getRef(position).getKey();
LocalDate expiry = LocalDate.parse(model.getExpiry());
LocalDate today = LocalDate.now();
long dayDiff = DAYS.between(today, expiry);
if(dayDiff <= 7){
holder.cardViewIngredient.setBackgroundColor(Color.parseColor("#FFD1D1"));
expiryNote.setVisibility(View.VISIBLE);
}
holder.ingredName.setText(itemName);
holder.ingredExpiry.setText(dayDiff " Days until expiry");
holder.deleteBtn.setOnClickListener(v ->{
// and here we will use the correct stored itemName instead of getting a new one
String output = fridgeRef.child(itemName.toString();
Log.d("Fridge" , output );
fridgeRef.child(itemName).removeValue();
});
}
This should fix your problem