This is my firebase database format:
-groups
-groupName
-groupId
-key1:"value1" -key2:"value2"
-key3:"value3"
I need to access value3 of key3.
I have the groupId.
Below is the code I've come up with. But when I run this my screen keeps crashing.
private void method_does_user_belong_to_this_group() {
expected_key3 = editText_expected_key3.getText().toString();
reference.child("groups").orderByChild(groupId+"/"+"key3").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
key3 = snapshot.getValue().toString();
if (key3.equals(expected_key3)) {
Toast.makeText(RoomJoiningPage.this, "Key3 found.", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(RoomJoiningPage.this, "Key3 not found"+key3, Toast.LENGTH_SHORT).show();
}
}
else {
Toast.makeText(RoomJoiningPage.this, "Key3 not found"+key3, Toast.LENGTH_SHORT).show();;
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
I've even tried this part too:
GroupDataClass groupDataClass = snapshot.getValue(GroupDataClass.class);
String key3 = groupDataClass.getKey();
by omitting this part from the above method:
key3 = snapshot.getValue().toString();
But even then my screen keeps crashing.
Any help is sincerely appreciated.
Edit-1
I've tried editing the code a bit so far. Now the crashing has stopped but the value I'm receiving is "null".
Log.d(LOG_TAG,"Debug Count - 12");
Log.d(LOG_TAG,"Entered else but didnt run the code below");
Toast.makeText(this, "Code entered.", Toast.LENGTH_SHORT).show();
reference_to_rooms_db = FirebaseDatabase.getInstance().getReference("rooms");
reference_to_rooms_db.orderByChild(string_current_users_number).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Log.d(LOG_TAG,"went inside \"onDataChanged\"");
if (snapshot.exists()) {
Log.d(LOG_TAG,"went inside \"if\"");
Log.d(LOG_TAG,"snapshot existed");
code = snapshot.child("code").getValue(String.class);
Log.d(LOG_TAG,"code copied - "+code+".");
Toast.makeText(RoomJoiningPage.this, "added code:"+code, Toast.LENGTH_SHORT).show();
Log.d(LOG_TAG,"toasted within \"if\"");
}
else {
Log.d(LOG_TAG,"went inside \"else\"");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d(LOG_TAG,"went inside \"onCancelled\"");
}
});
Related
the maxid integer variable should have the value for the getChildrenCount() from the firebase database, but it seems that the addValueEventListener is not working.
The following is my java code from Android Studio:
#IgnoreExtraProperties
public class ProfileID_Generator extends AppCompatActivity {
public int maxid;
private int ProfileID;
private String value;
private final DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("User");
public ProfileID_Generator(){}
public int profileID_generate(){
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
maxid = (int) snapshot.getChildrenCount();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
String val = snapshot.getValue(String.class);
value = val;
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
if(maxid==0){
ProfileID = 10001;
}
else{
ProfileID = Integer.parseInt(value)+1;
}
return ProfileID;
}
}
The following is the data from the realtime database from firebase:
All data is loaded from Firebase (and most cloud APIs) asynchronously, which changes the order in which code executes from what you may expect and be used to.
The problem is not that getChildrenCount isn't working, but that ref.child(Integer.toString(maxid)) is executed before maxid = (int) snapshot.getChildrenCount();. It's easiest to see this if you add some logging:
Log.i("Firebase", "Start loading maxid")
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
Log.i("Firebase", "Got data for maxid")
maxid = (int) snapshot.getChildrenCount();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
Log.i("Firebase", "Start loading ProfileID")
ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
String val = snapshot.getValue(String.class);
value = val;
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
When you run this code it logs:
Start loading maxId
Start loading ProfileID
Got data for maxid
This may not be the order in which you expected the output, but it is working as designed and explains perfectly why your code doesn't work: by the time you starting loading the ProfileID, the maxid isn't known yet.
The solution for this type of problem is always the same: any code that needs the data from the database has to be inside onDataChange, be called from there, or otherwise synchronized.
So the simplest fix is to move the code that loads the ProfileID into the onDataChange that sets maxid:
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
maxid = (int) snapshot.getChildrenCount();
ref.child(Integer.toString(maxid)).child("ProfileID").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
String val = snapshot.getValue(String.class);
value = val;
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
This is an incredibly common problem and stumbling block for developers that are new to asynchronous APIs, so I recommend reading up on some more questions about it, such as:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
Everything seems to be correct, but it does not work correctly. It says that the alias is busy even when it is not busy. It checks "players", it doesn't get to the name in it.
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference("players/" + playerName);
rootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.exists()) {
Name.setError("This alias is already taken");
} else {
}
}
#Override
public void onCancelled(DatabaseError error) {
}
});
I'm trying to execute some code in my addValueEventListener based on conditions of values in database, but when data changes, listener execute conditions based on old data, and at the second try listener perform data which I want to use. however data change listener perform listenr(-1) data. To be more clear, if "disable" or "stop" child exist I don't want to execute the code, but after data are updated and these children not existing, conditions when I call AddMessage method not executing again, but it execute method when I call for the second time, it perform correctly till next update of the data where it start again same issue.
sendMessage.setOnClickListener(new View.OnClickListener() {#Override
public void onClick(View v) {
AddMessage();
}
});
private void AddMessage() {
nListener = RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
if (!dataSnapshot.hasChild("disable") && !dataSnapshot.hasChild("stop")) {
HashMap <String,String> chatMessageMap = new HashMap <>();
chatMessageMap.put("from", messageSenderID);
chatMessageMap.put("type", "check");
chatMessageMap.put("content", messageText);
MessagesRef.child(messageReceiverID).push().setValue(chatMessageMap);
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
} else {
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String stoppedUser;
myDbref = FirebaseDatabase.getInstance().getReference().child("List Ref").child(<UID_OF_RECEIVER_OF_MESSAGE>);
myDbref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
stoppedUser = dataSnapshot.child(<UID_OF_SENDER>).child("stop").getValue().toString();
//Now use if-else statement
if(<UID_OF_RECEIVER> == stoppedUser){
Toast.makeText(getApplicationContext(), "You are blocked.", Toast.LENGTH_LONG).show();
} else {
AddMessage();
}
}catch (Throwable e){
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Though you can get <UID_OF_SENDER> by using FirebaseUser currentUserUID = FirebaseAuth.getInstance().getCurrentUser();
Make sure you put the value of <UID_OF_RECEIVER> correctly and also correct the database path if needed.
I am trying to fetch the data from the google firebase but every time i tried to fetch the data. "Else" case is running everytime. Tried to change if(dataSnapshot.exists()) but getting the same error. Please help to resolve it.
public void retrieveProfileInfo() {
currentUserID = mAuth.getUid();
key = rootRef.child("profiles").push().getKey();
rootRef.child("users-profiles").child(currentUserID).child(key)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
if ((dataSnapshot.child("name").getValue()) != null){
String retrieveName = dataSnapshot.child("name").getValue().toString();
String retrieveStatus = dataSnapshot.child("about").getValue().toString();
nameBox.setText(retrieveName);
aboutBox.setText(retrieveStatus);
} else {
Toast.makeText(UserProfileActivity.this, currentUserID+"else - retrieveProfileInfo()",
Toast.LENGTH_SHORT).show();
}
}catch (Exception e){
Log.i("retrieveProfileInfo : ", "error is : " + e);
Toast.makeText(UserProfileActivity.this, e+" : Error",
Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
You cant push a random key and read from it, you need to loop through children under users-profile/userID:
public void retrieveProfileInfo() {
//current user ID
currentUserID = mAuth.getUid();
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds:dataSnapshot.getChildren()){
//get the values
String name = ds.child("name").getValue(String.class);
String about = ds.child("about").getValue(String.class);
String uid = ds.child("uid").getValue(String.class);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// log error
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
};
rootRef.child("users-profiles").child(currentUserID).addValueEventListener(listener);
}
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.
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
}
}
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) {
}
});
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!