I am making a sample android app which shows all data present inside Firebase Database with the help of RecyclerView. It is working as I expected. Issue Is If I add More Items In Database As Time Passes. It would still get all data and show in recyclerView. It would be definitely slow (Due to internet and slow performance Of Devices) and would take some time to show data on recyclerView.
I heard of a way to resolve this by making them small chunks and loading another one when user scrolls further. This Process is known as pagination.
But In case Of Firebase Database, there is no direct way to paginate data in recyclerView. I have also searched for this issue on internet but none of them work.
Has anyone idea how to paginate firebase database data in recyclerView?.
Pagination Can Be Understood By This Sample Video
to do so you need to define two type of lists. One for major list which have all the elements and second one which have limit data.
private Query getQuery(String query) {
Query query;
if (recentLastItem == null) // recent last item is the any type of object which you have stored in the firebase
query = FirebaseDatabase.getInstance().getReference()
.child(your saved data location)
.orderByKey()
.limitToLast(no of elements per time you want);
// this if call when you try first time to get the items from firebase
else
query = FirebaseDatabase.getInstance().getReference()
.child(your save data location)
.orderByKey()
.startAt(recentLastItem)
.limitToFirst(no of items);
// this else part run when you try to get next no of items
return query;
}
get this query object and call value Listner on it. and one More thing you need to call getQuery() method whenever user reach the end screen of the device.
And do not forgot to update the value of last element from your list after seting the recyclerView.setAdapter(adapter) by calling recentLastItem = yourListName.get(yourListName.size() -1)
Related
I have a users collection with uId, name, photo
I have a visits collection with uId, userId, location
I have a recyclerview in which I want to show the location with the user name and photo
Can I use the reference field type? If so, how will Firestore know to link visits.userId == users.uId ?
Maybe I first need to query all the visits and then query the relevant user but 2 things:
It means querying a lot of times.
I didn't understand how to collect the joined collection into the adapter, which is based on one query?
Please advice
Thanks
current code
visitsList = db.collection("visitsList");
Query query = visitsList.whereEqualTo("userId",prefs.getString("id","")).orderBy("visitDate", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<AVisit> options = new FirestoreRecyclerOptions.Builder<AVisit>().setQuery(query, AVisit.class).build();
adapter = new VisitsListAdapter(options, VisitsListActivity.this);
RecyclerView rv = findViewById(R.id.rvVisitsList);
rv.setHasFixedSize(true);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(adapter);
The code is a simple query from the collection, not sure how to get the name and photo from the userId field in that collection.
Can I use the reference field type?
Yes, you can use a reference field.
If so, how will Firestore know to link visits.userId == users.uId ?
Firestore results always comes from a single collection (at the moment). It does not automatically join the document from the users collection when you're reading from the visits collection. You will have to do this yourself.
That indeed means you'll be executing multiple reads, but it's often not nearly as slow as you may think. See Google Firestore - how to get document by multiple ids in one round trip?
Update: To show data from the user profile in a list of visits, there are two main options:
load the additional user document in populateView or with a custom parseSnapshot implementation.
duplicate the relevant user data in the visits collection (which is quite normal in NoSQL databases). Also see Alex' answer here: indexed query with FirestoreRecyclerAdapter.
I am using FirebaseListAdapter in Android to display a list of Orders based off a certain date:
Query orderQuery = ordersRef.orderByChild("dateCreated").startAt(d1.getTime());
My Orders have a completed boolean property
-KsRHO1sLcVxKtVMec3o
completed: false
dateCreated: 1503713136950
I would like to only show not completed items in my list adapter.
the current query above retrieves all orders.
The issue is I don’t know how to query the database correctly to get this to work.
The only idea I have is in the populateView method of the FirebaseListAdapter to check if(!model.isCompleted()){ } and not fill in the textViews associated with the list item.
What way could I achieve my desired result?
in firebase there is not Multi Select or "Multi Query"
so you can orderByChild creating time Or compeleted
So you have to use the Method You mention in your Question
The only idea I have is in the populateView method of the
FirebaseListAdapter to check
if(!model.isCompleted()){ } and not fill in the textViews associated with the list item.
or you have to edit your database Structure
-completed
-KsRHO1sLcVxKtVMec3o
dateCreated: 1503713136950
and
-Notcompleted
-KsRHO1sLcVxKtVMec3o
dateCreated: 1503713136950
like when it`s completed .. remove it from notcompleted Node and
add it in completed node
You can try to use different references for completed and incomplete orders.
Initially when order is placed it will be in the incomplete state and when your order is updated then move the order with key in the complete reference.
Step 1:
Initially when order is getting placed, store the order in a "incomplete" reference like:
-incomplete:{
-anyRandomKeyGeneratedByFirebase:{
"orderTitle":"My First Order"... your order detail goes here
"orderKey":"anyRandomKeyGeneratedByFirebase"
},
.
.
.
}
Above structure will be for incomplete order.
When you know that your order status is completed then you will have to move order into the complete child reference like:
-complete:{
-anyRandomKeyGeneratedByFirebase:{
"orderTitle":"My First Order"... your order detail goes here
"orderKey":"anyRandomKeyGeneratedByFirebase"
},
.
.
.
}
So in this it will solve your problem. Rather than fetching all orders fetch only completed orders from complete reference.
-orders:{
-incompleteOrders:{
},
-completeOrders:{
}
}
If we query data from Firebase on a key for a child node, does it downloads the whole child node and filter data in the application or it downloads the query specific data? i.e. the filtered data
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId).orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {});
myTopPostsQuery will sort data according to starCount and I will receive data in the addChildEventListener() I want to know that whether this data is being filtered inside my app after receiving or my app downloads only the filtered data from the Firebase.
If you use a filter in your query you will download the query specific data without any operation executed on the client side.
Keep in mind that:
You can only use one order-by method at a time. Calling an order-by method multiple times in the same query throws an error.
You can combine multiple limit or range functions. For example, you can combine the startAt() and endAt() methods to limit the results to a specified range of values.
For any other info take a read here
You get the data already filtered. When you use a query, let say, limitToLast(10) you get only those 10 elements. This is happening also in your case with orderByChild("starCount"). In your SnanpShot will find only those filtered elements. Please visit official doc for more details.
Hope it helps.
Based on the code you pasted here, your query will just retrieve all the posts for the database path user-posts/<id> with an ordered manner which means that there is not filter. But still you will get back all the available posts under the path you are querying. It can be a "semi-filter" as it will find only the posts which include starCount field
The best thing is to filter during your query in order to retrieve back exactly what is needed and not everything as you are doing right now, imagine that this list of posts can be really big so you will have a big issue with performance later.
Read the following section here about sorting & filtering.
https://firebase.google.com/docs/database/admin/retrieve-data#orderbychild
Apart from that consider to add an index in userId field for speeding up your query.
I try to show data which i fetch from rest webservice (spring), in list(RecyclerView). Data can consist of thousands of rows. How should i use these data ?
should i fetch all data(or 100 rows ) and store them in local and read them from local to view in list. if i use these , how should i refresh local data ?
should i fetch 20 rows and view them , when user scroll down and arrive last item , i fetch another 20 rows ?
or should i use another way ?
If i store all data as array , it can throw outofmemoryexception . are there any tutorial or key words to search ?
How twitter or instagram use these data ? There can be a lot of items in twitter list ,but it doesn't crash and twitter can show items which downloaded before, offline(it means store data in local ,isnt' it ?)
To make app work smoother with RecyclerView, use Endless Scrolling.
Load 20 items at a time, apply pagination on your server API call.
Cache every response from server to local storage using OKHttp Response Caching.
Create a local database, store all data you already loaded inside the DB and add a "freshness" like a timestamp if your data is subject to change. If your data items are huge, consider loading an "index" of your data first, then load the individual details later.
Definitely you should not fetch all the data at once. Read about Pagination for dynamic data in android. Recycler View also uses inbuilt pagination for static data but in case of dynamic data i.e. when you are retrieving data from your api, you should send requests to your api when the user scrolls down the list to fetch the next set of data. In order to do that you'll have to extend RecyclerView's OnScrollListener and override the OnScrolled method.
I am writing an android chat app and I am trying to implement endless scrolling using Firebase Database in RecyrclerView using custom FirebaceRecyclerAdapter. For first messages load I get data from Firebase Database by using query that ordering data by .orderByChild() and then .limitToFirst(specificCount) so far so good. But when user scrolled to the last visible item I have to get next portion of messages and the problem comes I did not get a straight way to get messages from Firebase Database after specificCount. I tried with that code:
int startCount = mLayoutManager.getItemCount();
FirebaseDatabase
.getInstance()
.getReference()
.child(RequestParameters.FB_CHILD_MESSAGES)
.orderByChild(RequestParameters.FB_CHILD_MESSAGES_ORDERING_TIME)
.startAt(startCount)
.endAt(startCount + CustomFirebaceRecyclerAdapter.NEXT_MESSAGE_PORTION_COUNT)
.addListenerForSingleValueEvent(...)
But after I read the documentation for .startAt() I realize how stupid is this. Anyone could help to make a query that gets items after specificCount and limit received messages to some count.
I'm pretty sure I answered this less than a day ago, so I recommend scanning my answers. But I'll repeat.
The Firebase Database API is inherently not very well suited for pagination. Think of what happens when an item is inserted while the user is on page 1 (with the first ten items). They end up seeing the previous item 10 at the start of page 2, but will never have seen the newly inserted item.
That said, if you want to do pagination, it is technically possible. But instead of wanting to skip 10 items, you will instead have to tell Firebase to start the query at the last item from the previous page. This is called an anchor item and in code it looks like this:
FirebaseDatabase
.getInstance()
.getReference()
.child(RequestParameters.FB_CHILD_MESSAGES)
.orderByChild(RequestParameters.FB_CHILD_MESSAGES_ORDERING_TIME)
.startAt(timeOfLastItemOnPreviousPage, keyOfLastItemOnPreviousPage)
.addListenerForSingleValueEvent(...)
The key properties here are:
timeOfLastItemOnPreviousPage: the value of the FB_CHILD_MESSAGES_ORDERING_TIME property of the last item on the previous page
keyOfLastItemOnPreviousPage, the key of the last item on the previous page (which is needed in case there are multiple items with the same value for FB_CHILD_MESSAGES_ORDERING_TIME