I have implemented Firebase Firestore into my android application and it is retrieving data fine.
There is a calculation performed to sum up the values that are stored in the Firestore.
However, I believe with how I designed my code, there could be possible limitations on what can be done.
I have retrieved the data from Firestore and stored it into an ArrayList. So I can already see that when the ArrayList is initially populated from Firestore, any new data would not have updated the ArrayList.
I was thinking of maybe implementing a refresh button or a slide to refresh, but not too sure how to go about it.
The code is the same for the 2 sum sections and setting the value into the textview.
personTextView = v.findViewById(R.id.personSumValue);
final ArrayList<UserPaymentModel> personArrayList = new ArrayList<>();
db.collection("userspayment").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (queryDocumentSnapshots.isEmpty()) {
Log.d(TAG, "onSuccess: LIST EMPTY");
return;
} else {
List<UserPaymentModel> types = queryDocumentSnapshots.toObjects(UserPaymentModel.class);
// Add all to your list
personArrayList.addAll(types);
//Log.d(TAG, "onSuccess: " + mArrayList.get(2).getAmount());
double sum = 0;
for (UserPaymentModel u : personArrayList) {
if (u.getName().equals("Person1")) {
sum += Double.valueOf(u.getAmount());
}
}
Log.d(TAG, "onSuccess: " + sum);
personSumTextView.setText(String.valueOf(sum));
}
}
});
Basically there are 4 values and adding up the 2 values based on certain criteria will sum up the different values. If I add a new value, the recyclerview will be updated, but the sum shown at the top half of the screen does not update until I close and reopen the application.
If you want to update the values every time something is added on your Firestore Collection then you need to use a SnapshotListener instead of just getting the values once.
To do so, you need to replace db.collection("userspayment").get() with db.collection("userspayment").addSnapshotListener(EventListener). You can find more details in the documentation : Get realtime updates with Cloud Firestore
With this implementation no need to add a refresh as the data will come in real-time. All you need to do is to notify your Adapter that the data has changed using notifyDataSetChanged()
Related
I am using a filter query for a firebaseRecyclerAdapter (firebaseOptions).
Since I am using a searchView the recycler updates with every typed letter, if the query exists.
The problem is that I would like to clear the recycler if the query does not exist.
How can I add a check to see if the query is successful or not?
I am implementing a search, if the query exists I populate the recyclerview, if the query does not exist I want to clear the recyclerview.
public void fireSearch(String queryInput) {
String start = queryInput.toUpperCase(), end = queryInput.toLowerCase() + "\uf8ff";
Log.d("myTag", start + " " + end);
firebaseQuery = databaseReference.orderByKey().startAt(start).endAt(end);
searchRecyclerView.setVisibility(View.VISIBLE);
FirebaseRecyclerOptions<BusinessDetails> options =
new FirebaseRecyclerOptions.Builder<BusinessDetails>()
.setQuery(firebaseQuery, BusinessDetails.class)
.setLifecycleOwner(this)
.build();
}
If the query has no results, the FirebaseRecyclerViewAdapter will already clear the existing data. There is no need for you to handle this case yourself.
If you want to do some additional work when there is no data, you can override the onDataChanged method in your adapter class.
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(options) {
// ...
#Override
public void onDataChanged() {
// Called each time there is a new data snapshot. You may want to use this method
// to hide a loading spinner or check for the "no documents" state and update your UI.
// ...
}
#Override
public void onError(DatabaseError e) {
// Called when there is an error getting data. You may want to update
// your UI to display an error message to the user.
// ...
}
};
Also see the FirebaseUI documentation on data and error events, where I got the above code from.
I have a RecyclerView which is populated by posts stored in a Firestore database.
Each post is written as a document with a unique postID, storing the posted message, a timestamp and a like-counter.
//mUploads is defined as private List<Upload> mUploads;
//Upload object stores post message, timestamp and likes
mUploads = new ArrayList<>();
mFireStoreOrdered = mFireStoreInst.collection("posts").orderBy("time");
mFireStoreOrdered
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot doc : task.getResult()) {
//For each document get the ID
String postID = doc.getId();
// Upload object stores post message, timestamp and likes
Upload upload = doc.toObject(Upload.class).withId(postID);
mUploads.add(upload);
}
Collections.reverse(mUploads);
//Populate Recyclerview
mAdapter = new UploadAdapter(MainActivity.this, mUploads);
mContentView.setAdapter(mAdapter);
} else {
//...
}
}
});
When trying to implement the "like"-functionality for these posts I got to the limits of Firestore, which can only handle one document update per second.
Reading this article convinced me of using the Firebase Realtime Database to store the likes by using transaction operations instead of using distributed counters. I do not want to display the likes in real-time, I only want to use the RTDB to handle multiple likes/dislikes per second.
When additionally using the Firebase RTDB for likes, I would add data to a path /posts/postID/likes.
How can I get the post messages from Firestore and add the corresponding likes from the RTDB to mUploads before passing it to the adapter. Specificially, is it possible to ensure that I set the correct like value to its corresponding post, without querying for each postID.
This is a very common practice when it comes to Firestore, to store the number of likes in the Firebase Realtime database, otherwise you'll be charged for every read/write operation as explained in my answer from this post. So using Firebase Realtime database you can host the number of likes at no cost.
So, how can be done? First of all, you are guessing right. The number of likes should be added beneath the postId like this:
Firebase-root
|
--- likes
|
--- postIdOne: numberOfLikes //must be stored as an integer
|
--- postIdOTwo: numberOfLikes //must be stored as an integer
|
--- //and so on
To achive what you want, you need to follow the next steps.
Every time you you add a new post, add the corresponding post id in Firebase Realtime database like above by setting the value of that particular post id to 0.
Every time you get a new like increase the value of that postId by one. Every time a user retracts a like, decrease the value of that postId by one. To achieve this and also to have consistent data, I recommend you use Firebase Transactions.
Then in your adapter class, where you are displaying data from Firestore, when you want to set the number of likes to a view, just attach a listener on that particular post id node and get the number of likes. Inside the onDataChange() set that number to a TextView like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference noOfLikesRef = rootRef.child("likes").child(postId);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String numberOfLikes = "(" + dataSnapshot.getValue() + ")";
numberOfLikesTextView.setText(numberOfLikes);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
noOfLikesRef.addListenerForSingleValueEvent(valueEventListener);
That's it!
I am using firebase recyclerview to populate my data and retrieving those data from firebase realtime database. I don't want to retrieve all of my data but with a condition that is if "Available == yes " then show me the data in recyclerview. My condition is working but the problem is I have 4 data set on firebase realtime database. From them in 3 set value of available is yes .So, I supposed to get 3 list of data but I am getting all 4 set. 3 set data has actual value and 1 set taking the dummy one. How can I stop that?
FirebaseRecyclerAdapter<BloodModelSchema, UserViewHolder> firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<BloodModelSchema, UserViewHolder>(
BloodModelSchema.class,
R.layout.search_card,
UserViewHolder.class,
databaseReference
) {
#Override
protected void populateViewHolder(UserViewHolder viewHolder, BloodModelSchema model, int position) {
if(model.getAvailable().equals("Yes"))
{
viewHolder.setDetails(model.getBlood_Group(),model.getName(),
model.getArea(),model.getMobile(),
model.getEmail());
}
}
};
recyclerView.setAdapter(firebaseRecyclerAdapter);
firebaseRecyclerAdapter.notifyDataSetChanged();
If you have one databaseReference just add .limitToFirst(3)
FirebaseRecyclerAdapter<BloodModelSchema, UserViewHolder> firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<BloodModelSchema, UserViewHolder>(
BloodModelSchema.class,
R.layout.search_card,
UserViewHolder.class,
databaseReference.limitToFirst(3))
) { .....
But you can create second databaseReference2 and limit it to 4.
For different cases use two different adapters with different limitations. Good luck!
i want to make this type of collection in my firestore
where chatRooms will be my collection name, combination of myUid and opponentsUid will be my sub-collection in which different documents will be placed. My problem is i want to check if my collection contains sub-collection named myUid_opponentsUid or opponentsUid_myUid and i am not able to search a best query for doing this.
All i know is that we can fetch the whole list and then check if it contains the specific room or not, but its a lengthy process, so i want to better method for it.
Thanks in advance.
There are a few misconceptions in your question to clear up first:
In Firestore collections don't really exist as distinct entities. It's the documents inside a collection that cause it to become visible.
Also, collections can only contain documents, which in turn can contain collections, but the structure must alternate, so you can't have a collection called chatRooms that contains a collection myUid_opponentUid. Inside chatRooms there must be a document.
So if chat rooms contain messages, a straightforward way to do what you want is to create a document that represents that chatRoom. Then within that create a subcollection for the messages.
If you sort the UIDs before creating the composite chatRoom key you can then test whether or not the chat room exists by using a single get(). The structure would look like this:
chatRooms/(uid-pair)/messages/(message-id)
Note that you don't actually need to store anything at the chatRoom/(uid-pair) level to create children at the messages level: you can just create new messages and listen directly.
Try to Read Total Number of child .! Hope this thing may helps you.and if you want to implement your own api then try using Firebase Functions..and last thing I want to add is that if You want to add get Count without reading number of child you have to implement one method that getChildCount before storing data and then append them with key like JiGh_31GA20JabpZBfa,1` and only read keys and then use comma separator and you will get your result that this parent contains child or not.?
DatabaseReference myRef = database.getReference();
//You can use the single or the value.. depending if you want to keep track
String id= UUID.randomUUID().toString();//randomID for task
Object object=new Object ();
public int chidcount(String child){
string childcount="0";
//You can use the single or the value.. depending if you want to keep track
myRef.child(child).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snap: dataSnapshot.getChildren()) {
childcount=snap.getChildrenCount();
Log.e(snap.getKey(),snap.getChildrenCount() + "");
}
addvalue(childcount);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private addvalue(String childcount){
object=setid(id);
object=setname("name");
getchildCount("object");
mdatabaseRef.child("rating").child(manager.getId()+childcount).child(currentEmployee.getId()).child(id).setValue(rating);}
I know I am late.
Posting for future users.
Try this:
DocumentReference datab = db.collection("collection_name").document("Doc_name");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.contains("field_name"))
{
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
}
});
For Firebase Firestore to check whether the document has entries (fields), Use this command
firebaseFirestore.collection("Users").document(userId)
.addSnapshotListener {
documentSnapshot, _ ->
if (documentSnapshot!!.contains("name")) {
Log.i("Name", "Name exists")
} else {
Log.i("Name", "Name doesn't exists")
}
}
final FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter(Service.class, R.layout.browse_service_detail, ServiceHolder.class, mReference){
#Override
protected void populateViewHolder(ServiceHolder serviceHolder, Service service, int position) {
serviceHolder.setServiceName(service.getName());
serviceHolder.setInfo("От " + service.getPrice1());
service.setQuantitySelected(service.getQuantityEnabled());
if (Order.getInstance().getServices() != null) {
for (Service serviceFromSingleton : Order.getInstance().getServices()) {
if (serviceFromSingleton.getName() == serviceHolder.getServiceName().getText().toString()) {
serviceHolder.getServiceName().setSelected(true);
serviceHolder.getServiceName().setTextColor(getResources().getColor(R.color.yellow));
}
}
}
//add item to array
servicesList.add(service);
}
}
};
When I run this activity, it records the visible list objects to an array, but when I scroll down and go back up, it duplicates the first elements again into the array. How to fix it? For an item to be added only once.
I don't think there is any issue in RecyclerAdapter..I think the list only inserting same data multiple times.
why not you check whether the list is empty or not before adding data into it and clear the data if its not empty and then add new.
if(servicesList.isEmpty())
servicesList.add(service);
//else clear and add data
else{
servicesList.clear();
servicesList.add(service);
}
To handle data duplicacy, you can use a Set which will ignore duplicate inserts on scrolling.
servicesList.add(service);
Set<Service> mSet= new HashSet<Service>();
mSet.addAll(servicesList);
servicesList.clear();
servicesList.addAll(mSet);
OR use Set other than ArrayList
little clumsy but will work for you.