So I have this loop which means to loop through a list of products and check if they are sold out or the stock needs updating. But somehow it's infinite, I used the debugger went through with a few breakpoints it just kept looping back that's how I know its infinite after I had a look through and I couldn't find the issue
public void removeProductsFromDB(ArrayList<String> products) {
for (String ID : products) {
productsRef.child(ID)
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
ProductModel model = snapshot.getValue(ProductModel.class);
int ordered = 1;
int newQuantity = Integer.parseInt(model.getpQuantity()) - ordered;
model.setpQuantity(String.valueOf(newQuantity));
if (newQuantity < 1) {
model.setStatus("Sold");
} else {
}
DatabaseReference prod = FirebaseDatabase
.getInstance().getReference().child("Products");
prod.child(ID).setValue(model)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
loadingBar.dismiss();
showToast("Order Placed");
Intent intent = new Intent(ConfirmOrderActivity.this, HomeActivity.class);
startActivity(intent);
}
});
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
}
It's possible am just tired but I didn't think a for-each loop would turn out to be infinite.
CodePudding user response:
When you are using the Query#addValueEventListener() method, it means that you are attaching a listener that listens for real-time updates. This means that every change that takes place in the Realtime Database that corresponds to your productsRef.child(ID)
reference, will always trigger the onDataChange()
method. Since you are adding data inside the callback using:
prod.child(ID).setValue(model)
To the exact same reference you are listening to, your data gets written again. So this mechanism is happening over and over again, hence the behavior of an "infinite loop".
To solve this, simply change the above method call to Query#addListenerForSingleValueEvent(). This means that it will listen for changes only once.