I want to save whole Firebase data to device.
ValueListeners and ChildListeners have to be called a lot of times in the app. This becomes a little cumbersome. Sometimes it makes the app a little slow.
I know we can use setPersistenceEnabled, but in that case Listeners have to be called.
So, is there any way, in which we can save data (database) in device in a way, from which accessing the data can be fast and easy?
The only way to get data from the server onto your device is by attaching a listener. But a convenient way to attach a listener without coding it yourself, is by calling keepSynced(true) on a reference or query. The SDK in that case attaches an empty listener to the node(s), so that the data in the cache stays up to date.
Related
I am using Firestore for Android. I know it has persistence enabled by default.
Here is some background:
My app shows a list of notes and every note is tied to a label. Therefore while creating a note, I must present a list of labels (in a Dialog, in response to 'Select label' button), which will be provided to me by a snapshot listener on a Query. As creating a note is a separate Activity, each time user goes to create one, the complete list of labels must be presented.
My questions are:
Is snapshot listener smart enough to fetch the data from cache every other time, except for the first time? (And that "first time" will be after 30 mins when the listener expires, or Firestore clears the cache to save space, right?)
What is the impact of attaching and detaching listeners frequently? I am attaching the listener in Activity's onStart() and removing it onStop(). Here, the user may switch between apps to copy data from some other source to add it in the note, making listener detach/attach. Will this impact my read count?
How get() will behave in these scenarios? (I am not a fan of this as it isn't realtime)
Firestore keeps confusing me about the pricing as I dive deep into it. Need a good clarity on the behaviour of components around offline data and its pricing side.
Is snapshot listener smart enough to fetch the data from cache every other time, except for the first time? (And that "first time" will be after 30 mins when the listener expires, or Firestore clears the cache to save space, right?)
If you are offline, yes, Firestore will get all the data from the cache. This is happening when you are listening to real-time updates. On the other hand, if the real-time updates are not mandatory, you can simply use a get() call and specify the source, as explained in my answer from the following post:
How to include Source Cache in cloud firestore realtime update in MVVM architecture android
Regarding the cache limit, please check out the following answer:
What is offline data saving limit of Firestore?
What is the impact of attaching and detaching listener frequently? I am attaching the listener in Activity's onStart() and removing it onStop(). Here, user may switch between apps to copy data from some other source to add it in the note, making listener detach/attach. Will this impact my read count?
The listeners in Cloud Firestore are cheap, and you should not worry about lots of listeners attached to a document. Attaching and detaching the listeners is the way to go ahead with. It's mandatory to detach the listeners before the activity gets destroyed, as explained in my answer from the following post:
How to set addSnapshotListener and remove in populateViewHolder in RecyclerView Item?
How get() will behave in these scenarios? (I am not a fan of this as it isn't realtime)
When you are using get(), it means that you are getting the data only once. It's the correspondent of addListenerForSingleValueEvent() from Firebase Realtime Database.
Is it good practice to use --
query.keepSynced(true);
in Firebase recycler adapter? Will it help to make downloading of data less from the server?
Also how to disable persistence for a specific node though I am using --
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
In my Application class.
keepSynced effectively just leaves a listener attached to a location all of the time. If that's what you need, then use it. If not, then don't. It doesn't really have any other effect.
It's not really about good or bad practices, it's about making sure a location is always in sync with the server, if that's what you need. If anything, it causes more data to be downloaded than normal. The normal situation is adding a listener when the results of a query are being displayed, and removing that listener when that UI is gone.
You can't disable persistence for a specific node. Persistence is either on or off entirely.
I'd like to read all children of a node and then keep track of any changes that happen after that. One use case might be a local cache where I want to hold off using the cache until I know it's populated.
The one way I could imagine doing that is by first calling Query.addListenerForSingleValueEvent() to get the initial state. After I get the result, I know my local cache is populated, and I can now call Query.addChildEventListener() to get updates on when children are added and removed.
However, this seems inefficient - now the entire list of children is being sent across the wire twice, and I need to add a check to skip entries coming from addChildEventListener() that I already got from addListenerForSingleValueEvent().
It's not that big of a deal, but I wonder if there's a better way - isn't there a way to simply call addChildEventListener() and get a signal when all entries have been sent?
To both start synchronizing data and know when the initial synchronization has finished, you will need to add two listeners.
a ChildEventListener to handle the actual updates.
a ValueEventListener to detect when a complete update has been sent.
For the initial data from the database, your ChildEventListener.onChildAdded will be called first for each child node. After that the ValueEventListener.onDataChange will be called.
So as soon as onDataChange gets called, you can know that all initial data has loaded. If you only care about this initial data being complete, you can register this listener with addSingleValueEventListener so that it detaches after the initial synchronization.
Note that Firebase transfers data only once, even when there are multiple listeners for that data. So if you attach both listeners to the same location, the data will only be read once.
I have an android app that uses Firebase for the backend. In my database, I have a section called USER_NOTIFICATIONS which gets populated with some information when user's post gets liked.
Now, in the app, should I have a ChildEventListener that gets triggered any time a notification happens or should I have a SingleValueEventListener inside a function and call it every 20 seconds inside a Runnable? Is it expensive to run SingleEventListener in a Runnable?
The majority of the resource usage of a listener comes from the data it reads. When you attach a listener to a location, it reads the data from that location and fires the relevant events.
If you use addListenerForSingleValueEvent that's all it does. But if you use addValueEventListener or addChildEventListener, the listener stays active and will also be called if the data is updated afterwards.
a listener on a piece of data that never changes is quite cheap. But keeping a listener on data that changes frequently is as expensive as the size of the data changes.
In other words: there is no way to tell what to do without knowing all of the above. Without knowing those, I'd go for the simplest possible approach, put some measurements in place, and optimize as you discover more about your app's behavior.
I'm assuming you want to your app to respond to changes in the database, in which case you should use ChildEventListener. You can specify different behavior for 4 actions (onChildAdded, onChildChanged, onChildMoved and onChildRemoved).
I'm wondering if an Android Loader (more specifically AsyncTaskLoader) is the correct job for asynchronously submitting data to a web service.
The way I see it, most of the examples deal with grabbing data and displaying it to a user. For such operations things like having it "accidentally" hit the URL endpoint twice, or caching data is the norm.
However, when we're dealing with submitting data we want a way to absolutely make sure that:
the data is only submitted once
the submit operation is done anew each time we call it
we can pass a result back that will notify the user that the action was successful (or failed)
So, with that being said, how would I go about using the Loader pattern to send data in an asynchronous fashion? Are there any examples that exist for this type of use-case? Or is a Loader not the right thing, and I should be using something else altogether?
I don't agree with Nikolay on this one (I know how it sounds with my reputation against his;)). I use Loader (AsyncTaskLoader) to write data as well. More specifically I have an AsyncTaskLoader which checks for data on-line and then writes it to local database. It works like a charm and doesn't have AsyncTask drawbacks when it comes to persistence and leaking problems.
And it has the thing which you need (probably needed) - it doesn't run twice e.g. on configuration change, because it reconnects to the existing loader.
What you need to do is to put your submitting code in the loadInBackground() method and you're home.
You are probably looking for AsyncTask. The loader caches data internally and returns it to the app to be displayed by the app, it is not really designed to submit data. Why do you think you need to use a Loader for this?