Reputation: 1778
I have an issue with the following code : I don't understand why my for-loop doesn't loop before if (gameExists[0] == false){...
is called.
Button playButton = (Button) findViewById(R.id.play_button);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
user = mFirebaseAuth.getCurrentUser();
final String gameCateg = String.valueOf(categorySelected[0]);
DatabaseReference allExistingGamesToMatchKeys = mFirebaseDatabase.getReference().child("gamestomatchkeys");
allExistingGamesToMatchKeys.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
final boolean[] gameExists = {false};
Log.d("gameExists before loop ", String.valueOf(gameExists[0]));
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
final String currentKey = postSnapshot.getKey();
//check player 2 is not the same as player 1 so that we don't match the same player
if(gameCateg.equals(postSnapshot.getValue().toString())){
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player1").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String namePlayer1 = dataSnapshot.getValue(String.class);
if(!(user.getUid().toString().equals(namePlayer1))){
mFirebaseDatabase.getReference().child("gamestomatchkeys").child(currentKey).removeValue();
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player2").setValue(user.getUid());
gameExists[0] = true;
Log.d("gameExists in for loop ", String.valueOf(gameExists[0]));
Intent intent = new Intent(getApplicationContext(), Game.class);
intent.putExtra("gameIdKey", currentKey);
startActivity(intent);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
break;
}
}
if (gameExists[0] == false){
Log.d("gameExists in if", String.valueOf(gameExists[0]));
This is what I get in my logs, in this order :
gameExists before loop: false
gameExists in if: false
gameExists in for loop: true
I don't understand why I get
gameExists in if: false
before
gameExists in for loop: true
I want my loop to be called and entirely looped before if (gameExists[0] == false){...
, what should I modify ?
Thank you !
Upvotes: 1
Views: 680
Reputation: 2163
To make it simple, Firebase Database request are outside of the code flow. Take a look at this:
// here is first point
allExistingGamesToMatchKeys.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// here is second point
}
...
}
// here is third point
Above example will be executed like this
--> first point --> third point
Then where is the second point? Second point will be executed whenever Firebase get data from online database, so it is outside the flow (but most of the time, it will be executed after the third point.
So in conclusion, if you need some code to be executed after Firebase requests is done, place it inside onDataChange()
You might look at this for reference
Upvotes: 1
Reputation: 466
It's because "gameExists in for loop" is not actually in the for loop. It's in a callback that is created in the for loop.
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player1").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String namePlayer1 = dataSnapshot.getValue(String.class);
if(!(user.getUid().toString().equals(namePlayer1))){
mFirebaseDatabase.getReference().child("gamestomatchkeys").child(currentKey).removeValue();
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player2").setValue(user.getUid());
gameExists[0] = true;
Log.d("gameExists in for loop ", String.valueOf(gameExists[0]));
Intent intent = new Intent(getApplicationContext(), Game.class);
intent.putExtra("gameIdKey", currentKey);
startActivity(intent);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
Here you are creating a new instance of a ValueEventListener and you are overriding methods within it. Your are not executing the code within those methods at the point of instantiation. That code get called whenever your ValueEventListener decides to call the onDataChange() method.
I'm not entirely sure what this object is, or how it works:
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player1")
But if I were you, I would start by seeing if I could get a DataSnapshot from it, and using that snapshot on whatever code you want to execute outside of the Listener.
If I had to guess, there might be a method like:
mFirebaseDatabase.getReference().child("games").child(currentKey).child("player1").getDataSnapshot();
that you can call. Then copy all the code from inside onDataChange() to outside of the listener.
(I have no idea if that method exits, but I would assume there is some way of getting the current DataSnapshot)
Upvotes: 1