I think this is a crazy question but I'm new to firebase...Here is my problem...
I want to retrieve firebase data to textview, imageview and listview! this is my example database structure..it has many other nodes like this 😁
https://i.stack.imgur.com/JURr3.png
So, I add username to a textview, profile photo to imageview, birthdate to a textview and there are many other nodes like messages and other usernames(in an activity).It's ok but the problem is "it takes to much time to retrieve data to each view and then it shows all the data at the same time"..I mean it don't show each data simultaneously after loading but show all requested data to all views after loading. What I want is a view after a view loading and showing...😢😢
I don't know how to explain my problem and how to call it as I have bad Eng skill...😭😭
Here is UI of that activity after fetching data.(Birthdate and some data haven't added yet). https://i.stack.imgur.com/GRX0O.png This is the photo while retrieving with default image and text. https://i.stack.imgur.com/iEhv9.png
Step 1 :
Use Sqlite as a local database to store your data as well along wid maybe if u r using Firebase Realtime Database. Everytime a data is loaded for the first time , it will also be stored in the local database. So the next time when u open the app, u would see the results that u r expecting !
Step 2:
If u r using Firebase Realtime Database as a backend, make use of the Offline Data Handling feature which firebase provides. This too can solve your problem !
Not sure how you are feting data, ideally this should be the set of steps that you should be doing.
1) Fetch all the data(all children data as well) from that node and put it in a list.
2) Pass the data to a RecyclerView and populate it this was there wont be any lag.
This is an example code to fetch all the child nodes
myQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
// TODO: Add to list to send it to recyclerview
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
Hopefully, this will help you.
My personal advice is not to reach firebase data directly from client because of possible authentication and performance problems due to unintented implementation and usage of firestore api.
Instead, use Firebase cloud functions and write a service for what you need. To call those services from the app, you can use Firebase calls. You may suffer from cold boot but you can solve it with a warm up process ex. call those functions every minute with a cron job that can be set via cron-job.org
You can enable offline data in Firebase so every time you don't need to reload from the server first. First, you populate the data from the cache source and then silently load the data from the server source.
Enable Offline Data in Firebase
Related
I have a fragment in android where I read some data from firestore and than present it in the recycler view. the thing is it still working slow the same when device is go offline. I see in documentation that data persistence is on by default in firestore. here is the code:
firestore.collection(Constants.FireCollections.USERS)
.document(FirebaseAuthRepository().getCurrentUserId())
.collection("categories")
.get().addOnSuccessListener {
for (c in it) {
defaultCategories.add(c.toObject(Category::class.java))
}
Log.i(TAG, "Category: $defaultCategories")
binding.recyclerViewIcons.adapter = CategoryIconAdapter(defaultCategories, this#OutflowTransactionFragment)
}
I need this to work fast at least fast than reading from firestore online mode. and I want the online mode also to fetch the data locally from cached data instead of online for speed so when the device comes online it just update the catched data.
overall the desired result I want the speed.
Thanks for reading this.
The answer is very simple just by redirecting the call from the server to cache will do the magic.
If you are using Firestore in your app then you may notice a tiny delay in when you are getting data from Firestore in offline mode. and this because due to Firebase Firestore checks first in the server the data when it fails to load then again it takes the data from cache.
The problem and the tiny delay is because of two calls. so to overcome the delay we need get data from cache and this very simple by passing Source.CACHE to get() method. The default call is always from server so we need to add cache:
val source = Source.CACHE
firestore.collection(Constants.FireCollections.USERS)
.document(FirebaseAuthRepository().getCurrentUserId())
.collection("categories")
.get(source).addOnSuccessListener {
for (c in it) {
defaultCategories.add(c.toObject(Category::class.java))
}
Log.i(TAG, "Category: $defaultCategories")
binding.recyclerViewIcons.adapter = CategoryIconAdapter(defaultCategories, this#OutflowTransactionFragment)
}
Hope this help, let me know in the comment section if need for more clearification.
My firebase contains different data trees like Users, hobbies, class, scores etc. I want to get values from two sets of data “Users” and “hobbies”.
What is the best way to get values from the two tables?
Should I use firebaseDatabase.getReference() and then
dataSnapshot.child("Users").child(“name”).getValue().toString();
dataSnapshot.child("hobbies ").child(“track”).getValue().toString();
Or do I have to firebaseDatabase.getReference(“Users”) and firebaseDatabase.getReference(“hobbies”);
Since I noticed that firebaseDatabase.getReference() seem to refer to all data including the ones that are not needed(class, scores etc). Will this cause the app to slow down or does it have any implications?
If you attach a listener to a DatabaseReference, it will download/read all data under that reference. So if you attach a listener to FirebaseDatabase.getInstance().getReference(), you are reading all data in your database.
If you only need a subset of all data in your app, it's more efficient to only load that data. This means that you'll need to attach a separate listener to each branch of data that you need.
I have ViewPager which holds 2 different fragments. In both of the fragments, I'm trying to query firebase database with addValueEventListener. Here is the reference -
public static DatabaseReference getDatabase() {
if (mDatabase == null) {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
mDatabase = FirebaseDatabase.getInstance().getReference();
}
return mDatabase;
}
In first Fragment there is something like 500+ items (takes about 8 seconds to load up), and in the second there is like 20-30. The problem is that second fragment always wait for 1st one to finish and just then queries the second one. Is there a way I can separate or do something about it? I really need the second Fragment to load up faster. Thanks in advance.
If I had to solve this problem, I would think the overall situation a bit differently like #Mark suggested in the comments. I would have implemented a paginated query on Firebase so that I would not have to get all 500+ rows at a time.
Besides that, I would like to keep an offline storage of the data which are fetched from Firebase. So that, each time the application loads, the data is being populated in both fragments which were fetched earlier. I would run the query in the background asynchronously and the user would not have to wait for the query to finish to see the data in both fragments. Once the query is finished loading, I would have updated the views accordingly with the newly fetched data along with updating the local cache which will be needed to serve the data next time you launch the application.
If you are not interested in loading data in the background and showing the initial items from the cache and stick to your current implementation, then I would like to suggest you, manage all these things from the activity that contains the ViewPager. Just get the queries executed one after one, or asynchronously and get the results published to the fragments once the results are received from Firebase using BroadcastReceiver or something like that.
Hope that helps!
According to a response made by Yigit Boyar from Google, Live Data is not the best use case for a chat app, because it may lose displaying some items if they come at the same time. He recommends using the new Google's Paging Library. I've been using ItemKeyedDataSource for my inbox(all the people that have message the user), and the inside chat(the messages themselves). The problems are the following:
1- From the chat, when the user scrolls downwards, the user retrieves old messages, which means that the insertion of those messages should be in position 0 of the adapter, not sequentially like the paging library does. How can I alternate the position of the inserted items to be sequentially for new messages, and in position 0 for old messages?
2- From the inbox(people that have message the user), again I'm using ItemKeyedDataSource here, the problem is that I want to maintain the multiple document listener from the repository (I'm using Firebase Firestore), so I can detect every time a new person talks to the user. The problem is that callback.onResult is called only once, and fails when Firebase sends another user. How can I maintain an update-able list?
I understand that this answer is probably too late, but maybe it can help someone in future.
Position of item in RecyclerView is determined by the position of corresponding data object (of type T) inside PagedList<T>. PagedList is designed to look alike good old List<T>, but can be thought of as an "endless" list of elements.
PagedList gets its elements by pages on demand through something called DataSource.Factory. A Factory is used because DataSource by itself can only grow in one direction. If you need to prepend elements in PagedList, or change or remove existing elements you must invalidate the DataSource and a new instance will be created through DataSource.Factory.
So, to insert your data elements where you want them you should implement your own DataSource and DataSource.Factory by subclassing these base classes.
Note: Room, data persistence library from AndroidX, provides facilities to automatically generate instances of these classes for your data. You can write SQL query like this:
SELECT * FROM messages WHERE threadId=:threadId ORDER BY timestamp DESC
then get DataSource.Factory from this, use the factory to create LivaData<PagedList<Message>> and finally use the paged list to display messages in a RecyclerView in a chat application. Then, when you insert, update or remove data inside DB these changes will automatically propagate to the UI. This can be very useful.
I recommend you to read a few related examples a do codelabs:
https://codelabs.developers.google.com/codelabs/android-paging/#0
https://github.com/googlesamples/android-architecture-components/tree/master/PagingSample
https://github.com/googlesamples/android-architecture-components/tree/master/PagingWithNetworkSample
How to create offline first RecyclerView in Android so the users still can see the list when they don't have any internet connection?
I already know how to get parse JSON and populate it in RecyclerView, the problem is, users still can't access it when offline. And if I use cache using SQLite, how to update only the latest data from the server?
for example, I already got 3 data from server and populate it in RecyclerView like this:
Data 3
Data 2
Data 1
After that, there is an update from the server so there are 4 data from the server. I only want to add the 4th data without load from the 1st. And its going to be like:
Data 4 --> only add this to the RecyclerView without reload past data
Data 3
Data 2
Data 1
Regards,
Elmer
I have done something similar in this project:
https://github.com/isaacurbina/MyMovies/blob/master/app/src/main/java/com/mobileappsco/training/mymovies/Fragments/ResultsFragment.java
Basically, I use an AsyncTask to load data as the user scrolls down, loading more content (kind of like 9GAG or Pinterest do) managing a "page" counter.
Then, as I receive the data, I join it to the List object using list.addAll(results), being results another ArrayList<> of the same kind.
Then you can use adapter.notifyDataSetChanged() on your RecyclerViewAdapter and it will add them super fast, or you can use an animation to show them being added slowly.
I hope it helps, kind regards!