Load two depending datasets - android

I load two datasets in the onCreate function of my activity:
protected void onCreate(Bundle savedInstanceState) {
....
mDatabase.child("users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
currentUser = dataSnapshot.getValue(Users.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "error:", databaseError.toException());
}
});
mDatabase.child("events").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
...
event = dataSnapshot.getValue(Events.class);
if (event.getHost().equals(currentUser.getId()) {
....
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "error:", databaseError.toException());
}
});
String name = currentUser.getName();
....
}
So I need some data of the users dataset in the events dataset. Most of the time this works, but since they are called async, they are sometimes loaded in the wrong order. So events is loaded before users is loaded.
How can I fix this?

If you want to guarantee the order, you can nest the loading of the events into the callback for the user:
String name;
mDatabase.child("users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
currentUser = dataSnapshot.getValue(Users.class);
name = currentUser.getName();
mDatabase.child("events").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
...
event = dataSnapshot.getValue(Events.class);
if (event.getHost().equals(currentUser.getId()) {
....
}
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "error:", databaseError.toException());
}
});
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "error:", databaseError.toException());
}
});
The nesting becomes a bit deep, but if you pull the loading of events into a separate (named) method, that'll typically get better again.

Related

How to Get Nested Children From Firebase

I need to get the nested children (See Photo) from firebase. I would like to show a recyclerview that is only from a particular user. Below is what I have so far, but this is giving me all of the children.
DatabaseReference notificationInviteRef = FirebaseDatabase.getInstance().getReference().child(Strings.InvitesReference);
notificationInviteRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot1) {
ArrayList<Model_Notifications_Invite> model_notification_invites = new ArrayList<>();
for (DataSnapshot snapshot2:snapshot1.getChildren()) {
Model_Notifications_Invite invites = snapshot2.getValue(Model_Notifications_Invite.class);
model_notifications_invites.add(invites);
}
myNotificationsAdapter.updateNotificationsList(model_notifications_invites);
}
#Override
public void onCancelled(DatabaseError databaseError) {
//throw databaseError.toException();
}
});
If I understand correctly, you have two unknown levels in your data structure, which means you need two nested loops in your onDataChange: one for each level.
DatabaseReference notificationInviteRef = FirebaseDatabase.getInstance().getReference().child(Strings.InvitesReference);
notificationInviteRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot1) {
ArrayList<Model_Notifications_Invite> model_notification_invites = new ArrayList<>();
for (DataSnapshot snapshot2:snapshot1.getChildren()) {
for (DataSnapshot snapshot3:snapshot2.getChildren()) {
Model_Notifications_Invite invites = snapshot3.getValue(Model_Notifications_Invite.class);
model_notifications_invites.add(invites);
}
}
myNotificationsAdapter.updateNotificationsList(model_notifications_invites);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // 👈 never ignore errors
}
});

Get the child count from a Firebase database and put it on an array list

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.

firebase gets data too many times

I used recyclerview, arraylist, and firebase to get and show data, but data is added to the list too many times..
This is my code
database=FirebaseDatabase.getInstance();
mRef=database.getReference("SETS");
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot==null) return;
for(DataSnapshot userSanpshot : dataSnapshot.getChildren())
{
if(userSanpshot.child("DETAIL").getValue()==null) break;
single.Detail=userSanpshot.child("DETAIL").getValue().toString();
/~/
list.add(single);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
adapter.setItems(list);
and this is my code when I send data to firebase
Button sharebut=(Button)findViewById(R.id.usersend);
sharebut.setOnClickListener(
new FloatingActionButton.OnClickListener() {
#Override
public void onClick(View view) {
mDatabase.child("SETS").child(userId).child("DETAIL").setValue(detailText.getText().toString());
/~/
finish();
}
}
);
}
Try Using this method
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// do here your work
}
#Override
public void onCancelled(DatabaseError databaseError) {
// handle error here
}
});

Nested queries in firebase

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) {
}
});

Make sure that all Firebase single ValueEventsListeners finished

As mentioned in docs, it's better to fetch additional data, than nest objects in database.
According to this, how can I ensure that all data came?
I came up to this solution, but I'm not sure if this will work.
mPetsReference.addValueEventListener(new ValueEventListener() {
private List<Pair<Pet, Owner>> mData;
private long mChildrenCount;
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mData = new ArrayList<>();
mChildrenCount = dataSnapshot.getChildrenCount();
for (DataSnapshot data : dataSnapshot.getChildren()) {
Pet pet = data.getValue(Pet.class);
mOwnersReference.child(pet.getOwnerId())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mData.add(new Pair<>(pet, dataSnapshot.getValue(Owner.class)));
if (mData.size() == mChildrenCount) {
everythingCame();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
mChildrenCount--;
if (mData.size() == mChildrenCount) {
everythingCame();
}
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Categories

Resources