Android Firebase wait for data - android

in my android application I create an activity which contains a ListView which is populated with data from Firebase Database.
The JSON Tree of the structure of the database is the following:
{
"companies" : {
"companyX" : {
"address" : "50th avenue, NY",
"name" : "Spare-Tools Ltd."
},
"companyZ" : {
"address" : "50th Broadway, NY",
"name" : "Burgers and Burgers"
}
},
"company-requests" : {
"companyX" : {
"req1" : true
"req2" : true
}
},
"requests" : {
"req1" : {
"destination" : "Upper Tooting 122, Bronx",
"origin" : "Philadelphia",
"time" : "1473593287",
...
}
"req2" : {
...
}
}
}
I want to populate the ListView with the list of requests from the requests node. But I first need to know all requests that belong to a specific company so I first go to the company-requests node and retrieve all the request-keys belonging to the specific company.
The problem I am facing is that the ListView is created before the final data from the database arrived:
public class RequestsListActivity extends AppCompatActivity {
private ListView rListView;
DatabaseReference rootNode = FirebaseDatabase.getInstance().getReference();
#Override
protected void onCreate(Bundle savedInstanceState) {
...
rListView = (ListView) findViewById(R.id.result_list_view);
//First I retrieve all the requests of a specific company
DatabaseReference companyRequests = rootNode.child("company-requests/companyX");
companyRequests.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Then I retrieve all the keys of these requests
...
while (iterator.hasNext()) {
String key = iterator.next().getKey();
//For each key I retrieve its details from the requests node
DatabaseReference currRequest = rootNode.child("requests/" + key);
currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String time;
time = (String) dataSnapshot.child("time").getValue();
Request request = new Request(time);
allRequests.add(request);
}
...onCancelled...
});
}
//THIS CODE IS EXECUTED TO EARLY: BEFORE WE HAVE ANY DATA FROM FIREBASE
RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
rListView.setAdapter(adapter);
}
...onCancelled...
});
}
}
How can I insert a wait (spinner?) that waits until the values are loaded from Firebase?

You can use a simple counter to keep track of the number of pending loads:
companyRequests.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
// at the start we need to still load all children
final long[] pendingLoadCount = { dataSnapshot.getChildrenCount() };
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
//For each key I retrieve its details from the requests node
DatabaseReference currRequest = rootNode.child("requests/" + childSnapshot.getKey());
currRequest.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
String time;
time = (String) dataSnapshot.child("time").getValue();
Request request = new Request(time);
allRequests.add(request);
// we loaded a child, check if we're done
pendingLoadCount[0] = pendingLoadCount[0] - 1;
if (pendingLoadCount[0] == 0) {
RequestAdapter adapter = new RequestAdapter(RequestsListActivity.this, allRequests);
rListView.setAdapter(adapter);
}
}
...onCancelled...
});
}
}
});

I solved this using a java.util.concurrent.CountDownLatch:
In this example, replace EquityTotalListener with your implementation of ValueEventListener.
private void recalculate() {
final AtomicLong sumUpAll = new AtomicLong();
final CountDownLatch cnt = new CountDownLatch(mapUid2GeoLocation.keySet().size());
for (final String uid : mapUid2GeoLocation.keySet()) {
EquityTotalListener el = mapUid2EquityListener.get(uid);
if (el != null) {
if (logger.isDebugEnabled()) {
logger.debug("Listener for " + uid + " already set up");
cnt.countDown();
}
} else {
el = new EquityTotalListener(database.getDatabase(), uid) {
#Override
public void onCancelled(final DatabaseError databaseError) {
super.onCancelled(databaseError);
cnt.countDown();
}
#Override
protected void valueChanged(final String key, final Object value) {
if (value != null) {
sumUpAll.getAndAdd(Long.parseLong(value.toString()));
cnt.countDown();
}
};
}.attach();
mapUid2EquityListener.put(uid, el);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Waitung for countdown..");
}
try {
final boolean allGood = cnt.await(10, TimeUnit.SECONDS);
if (allGood) {
if (logger.isDebugEnabled()) {
logger.debug("Done waiting, " + uid + " owns " + sumUpAll.get() + " equity");
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("Waiting for read operations ran into timeout");
}
}
} catch (final InterruptedException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getLocalizedMessage(), e);
}
}
}

Related

How to Get/Handle Synchronized Firestore Data Having Multiple Entries?

Need to Do:
Basically i want Firestore => collection "order" => docs having customerid and productid on each doc => onSuccess => add to OrderPOJOList => call getCustomerName() then getProductName() => get Names in order => add to respective ArrayList => in end combine all data from three arraylist (OrderPOJOList, CustomerName, ProductName) to CurrentOrderPOJOList => set to Adapter.
Problem:
the two listeners in getCustomerName() & getProductName() runs asynchronously and adds Name to arrayList randomly... all i want is to show data on Adapter in order but sometimes names get exchange on list due to listners running asynchronously.
What should i do to get my customer and product names from firestore in sequence to display?
public class CurrentOrders extends AppCompatActivity {
private List<CurrentOrdersPOJO> currentOrdersPOJOList;
private List<OrderPOJO> orderPOJOList;
private FirebaseFirestore firebaseFirestore;
private String DocId, Area, cname, pname;
private OrderPOJO orderPOJO;
private CurrentOrdersPOJO currentOrdersPOJO;
private int count = -1, count1 = -1, i;
private RecyclerView recyclerView;
private List<String> customerName, productName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_current_orders);
//Current User Unique ID
DocId = getIntent().getStringExtra("DocumentId");
Area = getIntent().getStringExtra("Area");
Log.w("ReachedCurrentOrders", "Doc Id: " + DocId + "\nArea: " + Area);
currentOrdersPOJOList = new ArrayList<>();
customerName = new ArrayList<String>();
productName = new ArrayList<String>();
orderPOJOList = new ArrayList<>();
recyclerView = findViewById(R.id.activity_current_order_recyclerView);
firebaseFirestore = FirebaseFirestore.getInstance();
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
firebaseFirestore.collection("order")
.whereEqualTo("area", Area)
.whereEqualTo("status", "active")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(final QuerySnapshot queryDocumentSnapshots) {
if (!queryDocumentSnapshots.isEmpty()) {
for (final QueryDocumentSnapshot queryDocumentSnapshot : queryDocumentSnapshots) {
count++;
}
for (final QueryDocumentSnapshot queryDocumentSnapshot : queryDocumentSnapshots) {
orderPOJO = queryDocumentSnapshot.toObject(OrderPOJO.class);
orderPOJOList.add(orderPOJO);
Log.d("Tagging", "The Customer UID: " + orderPOJO.getC_uid() + "\nThe Product Doc ID: " + orderPOJO.getP_docid());
count1++;
if (count == count1) {
getCustomerName();
}
}//endof for loop
} else {
Toast.makeText(CurrentOrders.this, "No Orders in Your Area", Toast.LENGTH_SHORT).show();
Log.d("CurrentOrder", "Exception Here");
}
}
});
}//endofOnCreate
public void getCustomerName() {
count1 = -1;
//Getting Customer Name from ID
for (i = 0; i <= count; i++) {
firebaseFirestore.collection("customer").document(orderPOJOList.get(i).getC_uid()).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
cname = documentSnapshot.getString("name");
customerName.add(cname);
count1++;
if (count1 == count) {
getProductName();
}
} else {
Log.d("CurrentOrders", "Exception Here" + documentSnapshot.exists());
}
}
});
}
}//end of function
public void getProductName() {
count1 = -1;
//Product Getting Name
for (i = 0; i <= count; i++) {
firebaseFirestore.collection("product").document(orderPOJOList.get(i).getP_docid()).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
pname = documentSnapshot.getString("name");
productName.add(pname);
count1++;
if (count1 == count) {
callAdapter();
}
} else {
Log.d("CurrentOrders", "Exception Here" + documentSnapshot.exists());
}
}
});
}
}//endofFunction
public void callAdapter() {
for (int i = 0; i <= count; i++) {
currentOrdersPOJO = new CurrentOrdersPOJO(customerName.get(i), orderPOJOList.get(i).getComplete_address(),
productName.get(i), orderPOJOList.get(i).getQuantity(), orderPOJOList.get(i).getStatus(), orderPOJOList.get(i).getArea(), orderPOJOList.get(i).getO_date());
currentOrdersPOJOList.add(currentOrdersPOJO);
}
recyclerView.setAdapter(new CurrentOrdersAdapter(currentOrdersPOJOList, CurrentOrders.this));
}//endofFunction
}//endofclass
[screenshot of an activity showing list that varies everytime][1]
[1]: https://i.stack.imgur.com/X48JF.jpg
A similar question has been asked on another thread, it seems that you can synchronously return data because the method itself is a task, you could try to use the Taks.await(task) method to wait for the operation to end maybe that's the answer you're looking for.
I Have solved this problem by using mentioned solution by #Ricardo above AND combining the solution with using Asynctask(Background Thread) as it was first giving IllegalStateException because of calling Tasks.await(task) on Main UI Thread.
So, Use: Tasks.await(task) on Aysnctask(Background Thread)

Not able to display ArrayList items into multi column ListView

In my LogCat I have these details which were pulled up from my firebase database.
06-05 16:14:09.454 D: 3. DataSnapshot VALUE : {familyName=Richardson, children=[Sam, Jin, Peter], fatherName=Daniel, checkInTime=Mon, Jun 05 04:13 PM}
06-05 16:14:09.456 D: 4. DataSnapshot VALUE : {motherName=Alice, checkOutTime=Mon, Jun 05 04:13 PM, familyName=Richardson, children=[Sam, Peter, Jin]}
I used multi-column ListView for displaying the below data. But, the problem here is I'm unable to display the children data as it is an ArrayList. Only the last value of the ArrayList is getting displayed in Children column.
How can I display all the values of an ArrayList in a multi column ListView. Can anyone suggest me?
This is my code:
checkInCheckOutDBReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int i = 0;
for (DataSnapshot ds: dataSnapshot.getChildren()) {
i++;
String fatherNameValue = ds.child("fatherName").getValue(String.class);
String motherNameValue = ds.child("motherName").getValue(String.class);
HashMap < String, String > record = new HashMap < > ();
Log.d(TAG, i + ". DataSnapshot VALUE : " + ds.getValue());
familyNameColumn = ds.child("familyName").getValue(String.class);
record.put(FAMILY_NAME_COLUMN, familyNameColumn);
for (DataSnapshot cds: ds.child("children").getChildren()) {
record.put(CHILD_NAME_COLUMN, cds.getValue().toString());
}
// CHECK IN TIME
checkInTime = ds.child("checkInTime").getValue(String.class);
record.put(CHECKIN_COLUMN, checkInTime);
// CHECKOUT TIME
checkOutTime = ds.child("checkOutTime").getValue(String.class);
record.put(CHECKOUT_COLUMN, checkOutTime);
for (DataSnapshot snap: ds.getChildren()) {
Log.d(TAG, "*Key: " + snap.getKey());
if (snap.getKey().equals("checkInTime")) {
myCheckIn = "1";
myCheckOut = "0";
}
if (snap.getKey().equals("checkOutTime")) {
myCheckOut = "1";
myCheckIn = "0";
}
if (snap.getKey().equals("fatherName")) {
myParent = fatherNameValue;
}
if (snap.getKey().equals("motherName"))
myParent = motherNameValue;
}
if (myCheckIn.equals("1")) {
record.put(PARENT_CHECKIN_COLUMN, myParent);
}
if (myCheckOut.equals("1")) {
record.put(PARENT_CHECKOUT_COLUMN, myParent);
}
list.add(record);
ReportAdapter adapter = new ReportAdapter(GeneratereportActivity.this, list);
reportListView.setAdapter(adapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
Put your adapter code outside your for loop,and also create new object for the variable record
ReportAdapter adapter = new ReportAdapter(GeneratereportActivity.this, list);
reportListView.setAdapter(adapter);
like this otherwise, every time the object will overwrite and you will only last value
checkInCheckOutDBReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int i = 0;
for (DataSnapshot ds: dataSnapshot.getChildren()) {
i++;
record = new //your object
String fatherNameValue = ds.child("fatherName").getValue(String.class);
String motherNameValue = ds.child("motherName").getValue(String.class);
HashMap < String, String > record = new HashMap < > ();
Log.d(TAG, i + ". DataSnapshot VALUE : " + ds.getValue());
familyNameColumn = ds.child("familyName").getValue(String.class);
record.put(FAMILY_NAME_COLUMN, familyNameColumn);
for (DataSnapshot cds: ds.child("children").getChildren()) {
record.put(CHILD_NAME_COLUMN, cds.getValue().toString());
}
// CHECK IN TIME
checkInTime = ds.child("checkInTime").getValue(String.class);
record.put(CHECKIN_COLUMN, checkInTime);
// CHECKOUT TIME
checkOutTime = ds.child("checkOutTime").getValue(String.class);
record.put(CHECKOUT_COLUMN, checkOutTime);
for (DataSnapshot snap: ds.getChildren()) {
Log.d(TAG, "*Key: " + snap.getKey());
if (snap.getKey().equals("checkInTime")) {
myCheckIn = "1";
myCheckOut = "0";
}
if (snap.getKey().equals("checkOutTime")) {
myCheckOut = "1";
myCheckIn = "0";
}
if (snap.getKey().equals("fatherName")) {
myParent = fatherNameValue;
}
if (snap.getKey().equals("motherName"))
myParent = motherNameValue;
}
if (myCheckIn.equals("1")) {
record.put(PARENT_CHECKIN_COLUMN, myParent);
}
if (myCheckOut.equals("1")) {
record.put(PARENT_CHECKOUT_COLUMN, myParent);
}
list.add(record);
}
ReportAdapter adapter = new ReportAdapter(GeneratereportActivity.this, list);
reportListView.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});

Adding listener to firebase having List like data

I have this structure in Firebase
"shared_items" : {
"-KgGHdgE3L_m6ppVgn99" : {
"_id" : 14,
"added_date" : "08/Mar/2017",
"shared_with_emails" : "{\"abc#abc*com\":{\"name\":\"Customer Care\"},\"xyz#xyz*com\":{\"name\":\"Customercare\"}}",
"user_display_name" : "Logged in user",
"users_email" : "loggedinUser#gmail.com"
}
}
My questions:
When I am saving JSON data in "shared_with_emails" key then my data is automatically appended with "\" slash. Is this normal or I am doing something wrong here?
How can I get entire node based on email Ids present in this JSON object.
Function to create JSON objects from provided contacts..
public class JsonUtils {
final private static String TAG = JsonUtils.class.getSimpleName();
public String ContactsToJson() {
ArrayList<ContactsModel> listOfContacts = new ArrayList<>();
listOfContacts.add(new ContactsModel("abc#gmail.com", "abc"));
listOfContacts.add(new ContactsModel("xyz#gmail.com", "xyz"));
listOfContacts.add(new ContactsModel("mnop#yahoo.com", "mnop"));
JSONObject jsonObjectChild;
JSONObject jsonObjectRoot = new JSONObject();
for (int i = 0; i < listOfContacts.size(); i++) {
ContactsModel model = (ContactsModel) listOfContacts.get(i);
try {
jsonObjectChild = new JSONObject();
jsonObjectChild.put("name", model.getContactName());
jsonObjectRoot.put(model.getContactMail(), jsonObjectChild);
} catch (JSONException e){
e.printStackTrace();
}
}
System.out.println(jsonObjectRoot.toString());
return jsonObjectRoot.toString();
}
public class ContactsModel {
private int id;
private String mContactName;
private String mContactMail;
public ContactsModel(String contactMail, String contactName) {
this.mContactName = contactName;
this.mContactMail = contactMail;
}
public String getContactName() {
return mContactName;
}
public String getContactMail() {
return mContactMail;
}
}
}
Json data on Firebase
You can use ArrayList<String> to have multiple emails saved under shared_with_email. When you retrieve your data, save it inside an object and search whether the object contains the email.
ArrayList<String> keys = new ArrayList<>;
rootRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(Datasnapshot snap:datasnapshot.getChildren()){
ArrayList<yourObject> current = snap.getValue();
if (current.shared_with_email.contains(someEmail)){
keys.add = snap.getKey(); //Check this, all we need is the key of our object. kd47qjB.... in this case
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Once you have all the keys. Add listeners.
for(String key: keys){
rootRef.child(key).addValueEventListener(new ValueEventListener(){
#override
public void onDataChange(Datasnapshot datasnapshot){
//You successfully added listener to the key where user has its email.
//Do your work here.
}
});
}
You will have to create a class yourObject which resembles the data in your firebase database.

Android Firebase create lists based on group membership

I'm trying to create a list that only contains items of a particular group. For example, I've created/written a "fruits" node and a "groups" node myself in the database console (including the groups' keys).
Relatively new to Firebase, so still trying to wrap my ahead around flattening data structures.
The JSON (showing "fruits" and "groups") looks like the following:
{
"fruits" : {
"apple" : {
"color" : "appleColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZKey" : true
},
"origin" : "appleOriginValueHere",
"size" : "appleSizeValueHere"
},
"orange" : {
"color" : "orangeColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZ" : true
},
"origin" : "orangeOriginValueHere",
"size" : "orangeSizeValueHere"
},
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
},
"groups" : {
"GroupABCKey" : {
"members" : {
"apple" : true,
"orange" : true
},
"name" : "Group ABC Name Here"
},
"GroupJKLKey" : {
"members" : {
"strawberry" : true
},
"name" : "Group JKL Name Here"
},
"GroupXYZKey" : {
"members" : {
"apple" : true,
"orange" : true
},
"name" : "Group XYZ Name Here"
}
} ...
...
}
Within the app itself, a user can create a list which copies the entire fruits node into their newly created list (see JSON further down for user-list-items). I'm then displaying the items using FirebaseRecyclerAdapter
Here is the code for how I'm doing that:
private void writeNewFruitList(String userId, String username, String email, String title) {
final String key = databaseReference.child("fruit-lists").push().getKey();
UserLists userLists = new UserLists(userId, username, email, title);
HashMap<String, Object> updatedListToAddMap = new HashMap<>();
HashMap<String, Object> itemToAdd =
(HashMap<String, Object>) new ObjectMapper().convertValue(userLists, Map.class);
updatedListToAddMap.put("/fruit-lists/" + key, itemToAdd);
updatedListToAddMap.put("/user-fruit-lists/" + userId + "/" + key, itemToAdd);
databaseReference.updateChildren(updatedListToAddMap);
final DatabaseReference subDatabaseReference = FirebaseDatabase.getInstance().getReference();
subDatabaseReference.child("fruits").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d(TAG, child.getKey());
Log.d("fruitValues::", dataSnapshot.getValue().toString());
final String fruitKey= child.getKey();
FruitModel fruitModel = child.getValue(FruitModel.class);
Map<String, Object> nodeValues = fruitModel.toMap();
Map<String, Object> childUpdates = new HashMap<>();
String new_path = "/user-list-items/" + key + "/" + fruitKey+ "/";
childUpdates.put(new_path, nodeValues);
subDatabaseReference.updateChildren(childUpdates);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "onCancelled", databaseError.toException());
}
});
}
Q: How can I implement this process using groups? E.g., a user creates a list and only wants the newly created list to contain fruits that are of GroupABCKey but they also want the details of those fruits (size, origin etc).
Q2: What's the best way to edit my FruitModel.java to account for the groups?
public class FruitModel {
public String size;
public String origin;
public String color;
public FruitModel() {
}
public FruitModel(String size, String origin, String color) {
this.size = size;
this.origin = origin;
this.color = color;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("size", size);
result.put("origin", origin);
result.put("color", color);
return result;
}
// getters & setters
}
Finally, here's what I believe the user-list-items node would look like if done correctly?
listKey1forUserA is what I am creating correctly (except for mapping the groups as mentioned previously).
listKey2forUserA is what I'm trying to accomplish - A user wants to create and populate a list only with items that are in "GroupJKLKey"
"user-list-items" : {
"listKey1forUserA" : {
"apple" : {
"color" : "appleColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZ" : true
},
"origin" : "appleOriginValueHere",
"size" : "appleSizeValueHere"
},
"orange" : {
"color" : "orangeColorValueHere",
"groups" : {
"GroupABCKey" : true,
"GroupXYZKey" : true
},
"origin" : "orangeOriginValueHere",
"size" : "orangeSizeValueHere"
},
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
},
"listKey2forUserA" : {
"strawberry" : {
"color" : "strawberryColorValueHere",
"groups" : {
"GroupJKLKey" : true
},
"origin" : "strawberryOriginValueHere",
"size" : "strawberrySizeValueHere"
}
}
}
Is this the proper way to go about this? Any help or a point in the right direction would be great.
Although my usage has slightly changed since I originally posted this question, the two use cases below are still applicable with some minor adjusting. There's probably a better way to go about this, so I'd definitely welcome any suggestions or ideas from others.
The tl;dr is that you structure your database in such a way that you have a groups path and a users path. The users path contains no reference to groups. Get a datasnapshot of the children of a particular group (just need the keys) and add them to an ArrayList. > For each item in your ArrayList, plug that into the users path.
This will then allow access to the details of those users (or fruits, as used in my original question) and the ability to display that information or create new information however you see fit.
Create/Write a list of people based on group membership:
private void writeListFromGroupMembership(){
final DatabaseReference mainPathReference = FirebaseDatabase.getInstance().getReference();
final ArrayList<String> groupMembers = new ArrayList<>();
DatabaseReference groupsReference = FirebaseDatabase.getInstance().getReference()
.child("groups")
.child("someOtherChildYouMayHave")
.child("nameOfGroupYouAreInterestedIn");
/* Step 1: Get a list of people in a specific group that you are interested in */
groupsReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
String groupMemberKey = child.getKey();
if (child.getValue(Boolean.class) != null) {
groupMembers.add(groupMemberKey);
} else {
// TODO
}
}
/* Step 2: Loop through your list of people and insert them as a child like the following: */
for (int i = 0; i < groupMembers.size(); i++) {
final String singleGroupMember = groupMembers.get(i);
mainPathReference.child("all-groups").child("anotherChildYouMayHave").child(singleGroupMember)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Make a POJO for the item and immediately turn it into a HashMap
Person person= dataSnapshot.getValue(Person.class);
Map<String, Object> nodeValues = person.toMap();
// Make a map for the items you are adding
Map<String, Object> childUpdates = new HashMap<>();
// The path where the items will be copied/written to.
String newPath = "/master-list-items/" + listKey + "/" + singleGroupMember + "/";
// Add the items to the update map
childUpdates.put(newPath, nodeValues);
// Do the update
mainPathReference.updateChildren(childUpdates);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled: ", databaseError.toException());
}
});
}
}
// your other onCancelled override method here
}
Display a list of people based on group membership (using a Spinner, for example) :
public List<Person> persons;
...
private void getGroupMembers(String groupSelected) {
groupRef= FirebaseDatabase.getInstance().getReference()
.child("someOtherChildThatYouHouseGroupsUnder")
.child(groupSelected)
.child("members");
groupRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
String groupMember= child.getKey();
selectedGroupMembers.add(groupMember);
}
for (int i = 0; i < selectedGroupMembers.size(); i++) {
String singleMember = selectedGroupMembers.get(i);
singleMemberDatabaseReference = FirebaseDatabase.getInstance().getReference()
.child("all-people")
.child(singleMember);
singleMemberDatabaseReference .addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Person person = dataSnapshot.getValue(Person.class);
persons.add(person);
personAdapter = new PersonAdapter(getApplicationContext(), persons);
recyclerView.setAdapter(personAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG,"onCancelled: ", databaseError.toException());
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled: ", databaseError.toException());
}
});
}
For displaying a list of people based on group membership, my database structure is similar to:
{
"all-groups":{
"groupNameorKeyOfGroupName":{
"details":{
"meetingLocation":"110 William Street",
"someOtherChild":"Your value"
},
"members":{
"fakeUserA":true,
"fakeUserB":true,
"fakeUserC":true,
"fakeUserD":true
}
}
}
"all-users":{
"fakeUserA":{
},
"fakeUserB":{
}
}
}

Add items to a List in Firebase in Android

I am having a hard time trying to figure out how to add more items dynamically to a List in Firebase. As of now I am able to add just one item at the correct firebase location. The user needs to be able to add more items to the list. I am using a custom model class for the data. I would greatly appreciate any help, Thanks.
FloatingActionButton floatSave = (FloatingActionButton) rootView.findViewById(R.id.fabSave);
floatSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myFirebaseRef = new Firebase("https://you.firebaseio.com/");
myFirebaseRef = new Firebase("https://you.firebaseio.com/" + "/users/" + myFirebaseRef.getAuth().getUid());
String partyname = partyName.getText().toString();
String when = fromDateEtxt.getText().toString();
String timeOf = fromTimeEtxt.getText().toString();
String userItems1 = addThisItem.getText().toString();
userItems.add(userItems1);
Map<String,Object> values = new HashMap<>();
values.put("partyname", partyname);
values.put("When", when);
values.put("timeOf", timeOf);
values.put("userItems", userItems);
myFirebaseRef.push().setValue(values);
}
});
//Here is how I try to add additional items to the "userItems" List
final Button addItem = (Button) rootView.findViewById(R.id.buttonAddItem);
addItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SharedPreferences pref = getActivity().getSharedPreferences("MyPref", 0);
SharedPreferences.Editor editor = pref.edit();
String savedParty = pref.getString("thisPostKey", null);
myFirebaseRef = new Firebase("https://you.firebaseio.com/users/8d5d9915-54d8-4fc1-b92f-b45569e8089b/"+ savedParty + "/userItems");
String additem = addThisItem.getText().toString();
userItems.add(additem);
myFirebaseRef.push().setValue(additem);
System.out.println("There are " + thisKey + savedParty);
}
});
public class PartyPost {
private String partyname;
private String timeOf;
private String when;
private List userItems;
public PartyPost(String partyname, String timeOf, String when, List userItems) {
// empty default constructor, necessary for Firebase to be able to deserialize blog posts
this.partyname = partyname;
this.timeOf = timeOf;
this.when = when;
this.userItems = userItems;
}
public void setPartyname(String partyname) {
this.partyname = partyname;
}
public void setTimeOf(String timeOf) {
this.timeOf = timeOf;
}
public void setWhen(String when) {
this.when = when;
}
public void setUserItems(List<String> userItems) {
this.userItems = userItems;
}
public String getPartyname() {
return partyname;
}
public String getTimeOf() {
return timeOf;
}
public String getWhen() {
return when;
}
public List getUserItems() {
return userItems;
}
}
{
"users" : {
"8d5d9915-54d8-4fc1-b92f-b45569e8089b" : {
"-KDcHcfvc3CM-d8TWPE9" : {
"When" : "2-2-2017",
"partyname" : "Super Bowl",
"timeOf" : "5:00PM",
"userItems" : [ "Beer" ]
},
"-KDcHcjRbxXzCvRFa-No" : {
"userItems" : {
"-KDcLXIJ7I9TUFEDyyrA" : "Chips"
}
}
}
}
}
Your /userItems node has child node and per the question it has one child.
"userItems" : {
"-KDcLXIJ7I9TUFEDyyrA" : "Chips"
}
It appears you want to add additional children to that node. To add another child, you will need the path to that specific userItems node, here is pseudo-code
thisUsersUserItemsRef = /users/8d5d9915-54d8-4fc1-b92f-b45569e8089b/-KDcHcjRbxXzCvRFa-No/userItems
then push() the values
values.put("another_user_item", "docs ftw");
thisUsersUserItemsRef.push().setValue(values);
This will result in
"-KDcHcjRbxXzCvRFa-No" : {
"userItems" : {
"-KDcLXIJ7I9TUFEDyyrA" : "Chips",
"-JHoijoiqjodj8jkadiQ" {
"another_user_item": "docs ftw"
}
}
}

Categories

Resources