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!
Related
Let's say I have implemented an infinite scrolling list using Paging Library, but now I want to give the user an option to sort the data at client side, how can I do it? For example, I have movies data, the Paging library is working fine to load all movies, but how can I sort the movies based on say rating or release date.
Any help would be appreciated.
I haven't tried this method but hope it works .
Assuming you use RecyclerView to show the list (because it is much easier in recyclerView)
When you get the first ten item from server and you choose to sort it.Lets say by name(ascending) .You have to use two ArrayList here:
1:finalArrayList :- which contains all the whole list
2:updateArrayList :- which has the latest ten result
when you choose to sort (onButtonClick)
updateArrayList = new ArrayList<>();
updateArrayList.addAll(finnalArrayList);
Collections.sort(updateArrayList, new Comparator<StoreModel>() {
public int compare(StoreModel obj1, StoreModel obj2) {
// ## Ascending order
if (sortingBy == 0) {
return obj1.getName().compareToIgnoreCase(obj2.getName());
}});
adapter.clear();
adapter.addAll(updateArrayList);
Run this code only when the button is clicked
Now when you scroll down and more data comes
updateArrayList = new ArrayList<>();
updateArrayList.add(StoreModel)//Add the latest ten data from the response
and sort it before sending it to adapter
Collections.sort(updateArrayList, new Comparator<StoreModel>() {
public int compare(StoreModel obj1, StoreModel obj2) {
// ## Ascending order
if (sortingBy == 0) {
return obj1.getName().compareToIgnoreCase(obj2.getName());
}});
adapter.addAll(updateArrayList);
hope you got it and hope it works.Cheers:)
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()
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'm currently using FirebaseRecyclerAdapter to retrieve data from a Firebase database, and I've pretty much worked out how to retrieve the data in the order I desire.
To avoid duplication and ease database maintenance, I'd like to add a key to a database entry that allows me to return queries based on that key. I was originally storing data twice. Once for all to see, and once if a user had joined a certain group (under groupName).
To return a query based on group, my original search was as follows:
databaseReference.child(groupName).child("exerciseId"+mExerciseId).orderByChild(sortOrder).limitToFirst(100);
but I believe duplication can be avoided by adding the key "group" to my post. (it also make maintenance much easier as users switch groups).
The "group" database query has now become:
databaseReference.child("exerciseId"+mExerciseId).orderByChild("group").equalTo(groupName);
All is good, except that the data is no longer sorted as per "sortOrder". As firebase does not allow multiple sort criteria, I believe my solution lies in offline sorting.
So, how does one sort the adapter offline?
My adapter is pretty standard:
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post, PostViewHolder.class, dataQuery)
{
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position)
{
final DatabaseReference postRef = getRef(position);
// Bind Post to ViewHolder, setting OnClickListener for the star button
viewHolder.bindToPost(model, position, postRef.getKey(), null);
}
mRecycler.setAdapter(mAdapter);
}
I've implemented Comparable in Post, the problem is where is the data stored so that I can pass it to Collections.sort() in this sort of way:
private List<Post> mPosts = new ArrayList<>();
mPosts.add(model);
Collections.sort(mPosts, Post.Comparators.ALLTIME);
The adapters in the FirebaseUI library currently always display data in the order that it is returned by the underlying FirebaseDatabase reference or Query.
You could file a feature request on the Github repo for it (since I'm not sure it is covered in this one yet). Alternatively you could fork the library and roll your own implementation of this functionality.
To feedback on the solution I came up with. I ended up populating my own List, which I can then sort or add to (if using multiple queries) depending on what I'm trying to achieve. This is then displayed using a standard RecyclerView adapter. It works great.
private final List<Post> postList = new ArrayList<>();
dataQuery.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
postList.clear(); // in this example it's a newQuery, so clear postList
for (DataSnapshot child : dataSnapshot.getChildren())
{
Post post = child.getValue(Post.class);
postList.add(post);
int myPosition = sortData(); // uses Collections.sort() to sort data
mAdapter.addPosts(postList);
mAdapter.notifyDataSetChanged();
mRecycler.scrollToPosition(myPosition);
}
}
});
I am new to Android and just started to understand some concepts like the RecyclerView. I am using Firebase as a database so I implemented the Firebase solution for that.
My Adapter:
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
mDatabaseReference.child("offer").getRef()
) {
#Override
protected void populateViewHolder(OfferViewHolder viewHolder, Offer model, int position) {
if(tvNoMovies.getVisibility()== View.VISIBLE){
tvNoMovies.setVisibility(View.GONE);
}
viewHolder.tvHeading.setText(model.getHeader());
viewHolder.tvStoreName.setText(model.getStoreName());
}
};
Now I have two questions:
Is it possible to filter results inside the adapter or do i have to use ChildEventListeners for that?
When referencing to a key that contains an Array or an object itself how to retrieve child values?
You can initialize the FirebaseRecyclerAdapter with either a DatabaseReference or a Query. As its name implies, the latter allows you to get a subset of the children at a specific location in the database.
For example say if you want to only show offers from a specific store:
DatabaseReference offers = mDatabaseReference.child("offer").getRef();
Query storeOffers = offers.orderByChild("storeName").equalTo("A. lazzi's store");
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
storeOffers
) {