Why data in the firebase are created this way and not in the normal way
this is my code
ProductRef.child(IdMesa_1).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
facturas.setValue(dataSnapshot.getValue().toString()).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task)
{
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
When you call dataSnapshot.getValue().toString(), you're converting a branch of your JSON tree into a string. When you then write that back to Firebase, it saves it as a string.
If you want to save it in the same structure as before, don't convert the data to a string. So:
ProductRef.child(IdMesa_1).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
facturas.setValue(dataSnapshot.getValue());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Related
I have this database
I read key "20160877" to update type this is easy because there is one key.
by this way ==>
table_user.child("20160877").child("type").setValue("2");
If I put many keys like "20160877" and have value inside it and want to update type in all type in all keys how can I did this?
I tried this way but it create new key then update type in it, I want to update the existing data and not create new data
DatabaseReference table_user;
FirebaseDatabase database;
String id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_main);
database = FirebaseDatabase.getInstance();
table_user = database.getReference("Users");
}
public void current_member(View view) {
table_user.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
id =snapshot.getKey();
table_user.child(id).child("type").setValue("1");
Toast.makeText(AdminMainActivity.this, "تم تفعيل صفحة الاعضاء الحاليون", Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void active_C_page(View view) {
table_user.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
id =snapshot.getKey();
table_user.child(id).child("type").setValue("2");
Toast.makeText(AdminMainActivity.this, "تم تفعيل صفحة الترشح", Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
If you want to update the status of all users, you'll need to loop over the user nodes in the snapshot in your onDataChange.
So something like:
table_user.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot userSnapshot: snapshot.getChildren()) {
id = userSnapshot.getKey();
table_user.child(id).child("type").setValue("1");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
Or you can directly get the reference from the userSnapshot
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot userSnapshot: snapshot.getChildren()) {
userSnapshot.getReference().child("type").setValue("1");
}
}
I'm trying to get the count of "msanID" but it always returns the number as '0'. I'm using a separate class (ManageNodeName) to record the data and retrieving them back at list view.
I suspect the error is in the method of getting the String MSAN_NAMESP.
Any lead may help. Thanks!
List View
databaseNodes = FirebaseDatabase.getInstance().getReference("MSAN List");
#Override
protected void onStart() {
super.onStart();
databaseNodes.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
manageNodeList.clear();
for(DataSnapshot nodesnapshot: dataSnapshot.getChildren()){
progressDialog.dismiss();
ManageNodeName manageNodeName = nodesnapshot.getValue(ManageNodeName.class);
manageNodeList.add(manageNodeName);
MSAN_NAMESP = manageNodeName.getNodeID();
}
ManageNodeList adapter = new ManageNodeList(ManageSelectMSAN.this, manageNodeList);
manageListViewMSANs.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
query = FirebaseDatabase.getInstance().getReference("MSAN MTCE")
.orderByChild("msanID")
.equalTo(MSAN_NAMESP);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
int size = (int) dataSnapshot.getChildrenCount();
ManageNodeName.setCount(size);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Data is loaded from Firebase (and most cloud APIs) asynchronously. While the data is being loaded, your main code continues to run, so that the user can continue to use the app. Then when the data is available, your onDataChange is called with that data.
This means that all code that needs the data, needs to either be inside onDataChange or be called from there.
So:
databaseNodes.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
manageNodeList.clear();
for(DataSnapshot nodesnapshot: dataSnapshot.getChildren()){
progressDialog.dismiss();
ManageNodeName manageNodeName = nodesnapshot.getValue(ManageNodeName.class);
manageNodeList.add(manageNodeName);
MSAN_NAMESP = manageNodeName.getNodeID();
query = FirebaseDatabase.getInstance().getReference("MSAN MTCE")
.orderByChild("msanID")
.equalTo(MSAN_NAMESP);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
int size = (int) dataSnapshot.getChildrenCount();
ManageNodeName.setCount(size);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
}
ManageNodeList adapter = new ManageNodeList(ManageSelectMSAN.this, manageNodeList);
manageListViewMSANs.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
Also see: getContactsFromFirebase() method return an empty list for a longer example, and alternative approaches.
I fetched data from firebase database, inside OnDataChange method I want to perform another query based on the data I fetched previously. Before going to another activity I fetched all my data using a callback function MyCallback. Here listAllRequest contains expected data but userMap contains null. How can I ensure userMap contains data before going to another activity?
public void readRequestData(final Outgoing.MyCallback myCallback) {
groupDatabase = FirebaseDatabase.getInstance().getReference("Users").child(user.getUid()).child("outgoing");
userInfoRef= FirebaseDatabase.getInstance().getReference("UserInfo");
groupDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
listAllRequest.clear();
for(DataSnapshot childSnapshot: dataSnapshot.getChildren())
{
final BookRequestData bookRequestData = childSnapshot.getValue(BookRequestData.class);
listAllRequest.add(bookRequestData);
userInfoRef.child(bookRequestData.getOwnerId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user=dataSnapshot.getValue(User.class);
userMap.put(bookRequestData.getReqId(),user);
Log.e("outgoing",user.getName());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
myCallback.onCallback(listAllRequest);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
}
The code looks like this:
final DatabaseReference TuidRef = usersRef.child(td);
final DatabaseReference msgRef = TuidRef.child("rec_msg");
final DatabaseReference FuidRef = TuidRef.child("fromUID");
final DatabaseReference secretRef = TuidRef.child("rec_secret");
msgRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot1) {
ms = dataSnapshot1.getValue(String.class);
flag++;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
FuidRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot2) {
fUid = dataSnapshot2.getValue(String.class);
flag++;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
secretRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot3) {
st = dataSnapshot3.getValue(String.class);
flag++;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
String flagS = "" + flag;
Log.i("flag",flagS);
if(flag > 2)
displayMessage();
I used the flag to know how many times the ValueEventListeners are triggered, but the flag is found to be 0, in the log.
td is the uid of the person who receives the message. In the picture below it is same as the parent key of other sibling Childs.
The database looks something like this, when there are no messages:
The database looks like this, when messages are received:
Edit: How can I execute the function displayMessage(), when all three of the listeners have been triggered at once?
The value is added simultaneously to all three of them in the firebase database, though.
You'll never know how many times a ValueEventListeners is triggered in the way do, because the value of flag will always remain 0. This is happening due the asynchronous behaviour of onDataChange() method which is called even before you are trying to get the data from the database. What's really happening is that you are trying to get the data from the database and immediately try to log it while the flag variable has the initial value of 0. Then, when getting the data from the database completes, it changes flag's value, but it's never read again.
A quick solve for this problem would be add three different flags inside each callback and try to log then separately only inside the onDataChange() method like this:
msgRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot1) {
ms = dataSnapshot1.getValue(String.class);
flag1++;
Log.i("flag1", String.valueOf(flag1));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
FuidRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot2) {
fUid = dataSnapshot2.getValue(String.class);
flag2++;
Log.i("flag2", String.valueOf(flag2));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
secretRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot3) {
st = dataSnapshot3.getValue(String.class);
flag3++;
Log.i("flag3", String.valueOf(flag3));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
If you need in your code to get the value of that flag outside the onDataChange() method, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
Edit:
msgRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot1) {
ms = dataSnapshot1.getValue(String.class);
flag++;
FuidRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot2) {
fUid = dataSnapshot2.getValue(String.class);
flag++;
secretRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot3) {
st = dataSnapshot3.getValue(String.class);
flag++;
Log.i("flag", String.valueOf(flag));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
});
I have issues on nested queries I'm trying to do using firebase, seems like the first query (activity1) doesn't wait until the second (activity2) and third query (activity3) finished running, this might return NULL value from the first query. Please look at my sample for more understanding, I've been stuck here for days trying all kind of method but it just wont work. :(
Query query_1= reference.child("Users").child("Room")
.child("Profile");
query_1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 1
Query query_2 = reference.child("Users").child(Room)
.child("Receiver").child("id");
query_2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 2
Query query_3 = reference.child("chatrooms").child("Room")
.child("Creator").child("id");
query_3.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//ACTIVITY 3
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});