How to read continiusly a value change in Firebase (Android)?

I use Firebase for multiplayer. Everything works great except that I need when one player closes app (onStop(), onDestroy() etc) the game ends. I have the following firebase structure:

"PVP" : {
    "active" : {
      "1536394217496" : {
        "didGameEnd" : true,
        "gameMaster" : {
          "didPlayerAnswer" : false,
          "name" : "stelios",
          "playerAnswerCorrect" : false,
          "score" : 2
        },
        "gameSlave" : {
          "didPlayerAnswer" : false,
          "name" : "anna",
          "playerAnswerCorrect" : false,
          "score" : 4
        },

I have in onDestroy, onDestroy etc method to change the "didGameEnd" working fine. My problem is I need to catch the change to run the endgame code. I tried a lot but i cant manage it. Here is my code for this:

mGameFirebase = FirebaseDatabase.getInstance()
                .getReferenceFromUrl(Constants.FIREBASE_BASE_URL + Constants.FIREBASE_PVP + Constants.FIREBASE_GAME_ACTIVE_PATH + mGameWaitModel.getId());
public void ifGameEnds() {
        mGameFirebase.child("didGameEnd").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                Boolean isEnded = (Boolean) dataSnapshot.getValue();

                    if (isEnded == true) {
                        Intent intent = new Intent(getApplicationContext(), PvPWinningActivity.class);
                        Bundle dataSend = new Bundle();
                        dataSend.putString("Winning Text", winning_text);
                        dataSend.putInt("Your Score", your_Score);
                        dataSend.putInt("Opponent Score", opponent_score);
                        intent.putExtras(dataSend);
                        startActivity(intent);
                        finish();
                    }

                }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
    }

As i can understand the valueListener catches the datachange so i dont need to do something special here. I guess the problem is with the boolean value. I tried it as string with no luck.

Set value works fine so i guess i m pointing in the right place

mGameFirebase.child("didGameEnd").setValue(true);

Appriciate any help for what is wrong as i m new at Firebase!

After many tries the following code

mGameFirebase.orderByChild("didGameEnd").equalTo(true).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

   // this will be triggered only when the value is true, so you can add the thing that you want to make happen, here only

                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

works BUT it triggers even of the value is FALSE. So actually its just read the value, not doing what i need.

The following code

     mGameEnd =FirebaseDatabase.getInstance()
                        .getReferenceFromUrl(Constants.FIREBASE_BASE_URL + Constants.FIREBASE_TEST_PATH + Constants.FIREBASE_GAME_ACTIVE_PATH + mGameWaitModel.getId());
                mGameEnd.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {

                            boolean isEnded = dataSnapshot.getValue(Boolean.class);
if(isEnded) {
        //Your logic
    }


                    }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {

                }
            });

throws Nullpoint exception all the time.

Upvotes: 2

Views: 818

Answers (3)

For future reference the following code works:

// initialize the game state listener
        mGameEnd = FirebaseDatabase.getInstance()
                .getReferenceFromUrl(Constants.FIREBASE_BASE_URL + Constants.FIREBASE_TEST_PATH + Constants.FIREBASE_GAME_ACTIVE_PATH + mGameWaitModel.getId());
        mGameEnd.child("didGameEnd").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if(dataSnapshot.exists()) {
                    boolean isEnded = (Boolean) dataSnapshot.getValue();
                    if(isEnded){
                        if (isGameMaster()) {
                            your_Score = 0;
                            opponent_score = mGameModel.getGameSlave().getScore();
                            winning_text = "You Lost!";
                        }

                        if (!isGameMaster()) {
                            your_Score = 0;
                            opponent_score = mGameModel.getGameMaster().getScore();
                            winning_text = "You lost";
                        }
                        Intent intent = new Intent(getApplicationContext(), PvPWinningActivity.class);
                        Bundle dataSend = new Bundle();
                        dataSend.putString("Winning Text", winning_text);
                        dataSend.putInt("Your Score", your_Score);
                        dataSend.putInt("Opponent Score", opponent_score);
                        intent.putExtras(dataSend);
                        startActivity(intent);
                        finish();

                        Toast.makeText(getApplicationContext(), "Game Over", Toast.LENGTH_LONG).show();
                    }
                    else {
                        Toast.makeText(getApplicationContext(), "Keep Playing", Toast.LENGTH_LONG).show();
                    }
                }

Thanks a lot for the efford!

Upvotes: 0

Alex Mamo
Alex Mamo

Reputation: 138824

To set the value for your didGameEnd property from false to true, you need to use the following lines of code in your onStop() method:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference didGameEndRef = rootRef
    .child("PVP")
    .child("active")
    .child(uid)
    .child("didGameEnd");
didGameEndRef.setValue(true);

To constantly check if this value is changed, you should add the listener on the same reference like this:

didGameEndRef.addValueEventListener(/* ... */);

And inside the onDataChange() method, get the value using these lines of code:

if(dataSnapshot.exists()) {
    boolean isEnded = dataSnapshot.getValue(Boolean.class);
    if(isEnded) {
        //Your logic
    }
}

Upvotes: 2

PradyumanDixit
PradyumanDixit

Reputation: 2375

I am guessing that your mGameFirebase looks something like this:

DatabaseReference mGameFirebase = FirebaseDatabase.getInstance().getReference().child("PVP");

If it does, you can use childEventListener to listen to the changes in didGameEnd child of your database. The code does not have many changes just, simple additions :

mGameFirebase.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                Boolean isEnded = (Boolean) dataSnapshot.child("didGameEnd").getValue();
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {


            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {


            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

If your mGameFirebase points to the reference of the active or children below the main node, you can try this, which will only be triggered when the game ends and the value changes:

mGameFirebase.orderByChild("didGameEnd").equalTo(true).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

   // this will be triggered only when the value is true, so you can add the thing that you want to make happen, here only

                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

Upvotes: 1

Related Questions