In an effort to reduce data transfer (since it's costing us a lot of money), we're in the process of updating our Firebase Realtime Database value listener to use child listeners. Since most of the fields don't change, and the ones that change most frequently we only care about in certain app states, using only child added and child removed listeners seems to fit the bill.
Adding listeners for just child_added and child_removed appears to work perfectly on web. And iOS seems to be set up that way as well, though I admittedly haven't tested there yet. Android, however, appears to require that we add one massive listener that will listen for child moved and child changed too.
Listening for these, to my understanding, mostly defeats the purpose of using the child listeners over the value listener. Since any time any of the child's data changes (most of which we don't care about most of the time), it will send the entire child's snapshot again. We're trying to avoid data transfer by only listening for added/removed and circumstantially specific child properties, but this requires we basically listen to all of it at all times? Is there another way to implement this, to get what I'm hoping for?
To summarize our object, we have:
parent
--child A
----child A property 1
----child A property 2
--child B
----child B property 1
----child B property 2
etc. And we want to know when a child is added or removed, but most of the time we don't care about keeping the child's properties updated and would prefer to avoid re-transferring that data. How is that accomplished on Android (using Java, specifically)? Thanks!
There is no difference between the data transferred for a ValueEventListener vs a ChildEventListener when they are used on the same query/path in the database.
If you only want to know when a child is added/remove, but not about their contents, consider adding an additional top-level branch to your tree, where you keep just the key of the child node and then true as its value.
Related
Suppose we would like to retrieve 15 random children from questions node having this database structured as below:
1. The first (intuitive and discussed) way of retrieving random children from Firebase is to retrieve the whole required parent node (questions as dataSnapshot) and then select some random children on the client-side. This method has been pointed out in many posts, like in this one here .
Obviously, this method has its downsides; for example when querying through a large sized parent node (e.g. over 10.000 children) retrieving such an amount every time would result in a huge bandwidth usage as well as a client side burden. (when we actually require only a small amount of children)
2. Moving on: another approach, as described here which uses an iterator somehow bypasses the whole client side burden, yet the huge bandwidth usage could still occur as we download the whole parent node every time.
3. An interesting approach is described in Tom's answer in this firebase discussion which proposes:
A hacky way of doing this would be to generate a random key and do a query with startAt().limit(1). I have a feeling this could hurt the performance of your firebase though, so this should not be an operation you perform often. We don't have a real random sample function.
This solution actually sounds pretty good, yet I am not sure how it would indeed impact my Firebase.
4. Another silly solution could actually be naming the question ids manually, so to speak, from 0 to N, therefore handling the random group of ids on the client side and retrieving the questions spot-on by knowing the actual name of nodes.
5. And lastly, I have come up with the following solution to which I ask if is more or less viable than the ones presented above: creating another parent containing the question ids only and when needed, one should retrieve this parent which is much "lighter" than questions parent . From there, I would have the specific random ids and I would only need to snipe for those children. To better understand my meaning, please check the below picture:
Now, from this method arises the following issue: is assigning (let's say) 15 eventListeners good practice? Could this actually slow up things? (Note: this applies to methods 3 and 4 as well)
And ultimately, which method is actually the optimal one when querying from a large database for some random children?
You can use the classic solution as I explained in this answer but if you are afraid of getting huge amount of data then use instead 15 listeners. There is nothing wrong in using listeners as long as you remove them according to the life-cycle of your activity. So, IMHO go ahead with 15 listeners.
We have 2 case here
case 1
If you want to grab all details of the random ids at once, then I suggest 1 listener to the parent node (get value of datasnapshot using pojo class).
case 2
If you want to get the details independently upon request then you will have to attach a listener to each (random id) that you want.
Concerning performance
Try to use only Listener For Single Value Events as they listen one time and then stop (better for performance).
Dont use Value Event Listener (because these listeners keep checking for changes and therefore bad performance as listeners increase).
EDIT
lets say you listened to (questions_ids) node, now you have access to the random id keys, store them in a String variable, and then inside the same listener add another listener to (questions) pointing to the id that you want to grab details
//first listen to question ids ref (the one with 15 ids)
question_ids_ref.addListenerForSingleValueEvent(...{
//grab the key of each (random id) and store in variable
String random_01=......;
//run another listener this time to questions ref
questions_ref.child(random_01).addListenerForSingleValueEvent(..{
//get details of random_01 and so on....
});
});
I have a project that loads a list from the server. This data will eventually be stored into a database, but for now is stored in memory in a MutableLiveData. A RecyclerView's adapter is watching the data and displaying it. So far everything is working as expected, using a FAB the user can post a new entry which will go at the top of the list, on success I get a 200 and here's the main part where I'm getting lost...
When I want to add a single item to a list stored in a LiveData, the observer is unaware of the delta. I currently make a call to RecyclerView.Adapter.notifyDataSetChanged(), though the ideal in my case would be to call notifyItemInserted(0) or in other cases I can see various other notifications. What the best way to do this? The lifecycle architecture library appears to be very well thought of, I assume I'm missing something simple. I can't imagine having to manually perform a diff between the lists?
Currently I have implemented google analytics in my app to track specific user views and events. It is set up so that anyone that logs in with a user ID can show up in my 'userIDview'. Since google analytics doesn't query user data I was trying to figure out a way around it. I was wondering if there is any way to assign a specific view to the trackingId? Say for instance I set up a view 'MaleUserID' so I could track all the userIDs for men and look at their data separately from women, but I also had a 'WomenUserID' so I could look at their data as well. I was wondering if there is a way to set the trackingId and view together like:
trackingId: 'UA-XXXXX-1.MaleUserID',
so that all of their data would go only to the 'MaleUserID' view and none would go to the 'WomanUserID' view.
That is a pretty simple example, in actuality I will need more than two because I plan on filtering it by the subdomains that the users sign in to.
No.
Data is collected at the property level. Views are for displaying data. Specifying a view id would not make sense, since by default the same data goes into all the views. GA cannot separate data for you, you have to do it yourself via view filters.
If you want to have different types of data in different views you send all of the data to a property and then create view filters that separate data according to your criteria (which must refer to some data field that is send along in the GA tracking call). You cannot separate views at collection time.
I have read through the android documentation in https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.html
I don't understand the description stated in the document about recycle() and refresh() method.
1. recycle() - Return an instance back to be reused.
The instance is return back to where?
In which scenario this instance going to be reused?
AccessibilityNodeInfo might contains child node, do i need to call recycle() when my code navigate to each of the node or just call recycle method at root node?
2. refresh() - Refreshes this info with the latest state of the view it represents
I thought when onAccessibilityEvent() method was called, the AccessibilityEvent object should contain the latest state?
AccessibilityNodeInfo might contains child node, do i need to call refresh() when my code navigate to each of the node or just call refresh method at root node?
The Android Accessibility API uses a pool of AccessibilityNodeInfo nodes. That way, iterating over large trees will not create many objects that would slow down the garbage collector. In other words, when you recycle() a node, you might later (on the next event for example, or when iterating over the same tree) receive the exact same node object again, but filled with completely different details. That's why it is important you don't hold references to nodes you have recycled (and for example try to compare them to other nodes).
When you obtain child nodes, you have to recycle each child node. When you do not get them, you do not need to recycle them. You can recycle children before you recycle parents, or the other way round, depending on how long you will need access to the objects.
When you receive a node, it contains the latest state. But when you perform an action on it (e.g. click or scroll), the state of the node or of other nodes may change. If you want to see these changes in real-time (and not only when you receive the next event), you have to refresh() the node (or you can refresh() the root and try to obtain a new copy of the node from the root)
When you freshly obtain child nodes, you do not need to refresh them (they are already fresh). You only need to refresh nodes that you obtained earlier (before doing some interaction with them or with other nodes).
recycle()
In my (relatively brief) usage of an accessibility service, it seems you are not expected to call recycle(), or at least not on nodes you have not explicitly requested (e.g. through one of the functions mentioned below); I have received some fairly arbitrary crashes from this due to the backing cache (in the SDK) clearing nodes that it itself was holding on to (!) and I've looked at the source code and it appears all called nodes are added to a backing cache that later gets cleared. There are few ways to safely check if a node was already recycled and the SDK code definitely does not.
By holding on to nodes I have found that they eventually get recycled by some SDK code, too, thus my observation that it may not be expected for developers to do it themselves.
refresh()
At the time you receive a node, it is accurate. If you perform any actions that give you another node (getChild(i), findAccessibilityNodeInfosByViewId(viewId), etc.), the SDK calls a function to retrieve fresh info -- so it will be accurate at the time.
It seems to be relatively safe to hold on to nodes so long as you check their validity; However, most fields nevermind functions will throw an exception if the node has already been recycled somewhere. So: I would recommend you create yourself a convenience isValid() function to check this on all nodes.
Just check that it isn't null (some events will give you a null source!) and that the className attribute is not null (always safe to check, and is nulled when unused or recycled).
I have a Fragment, and once the user presses OK, an Item is added to my database and its ID is added to the ArrayAdapter. Immediately after, the adapter tries to draw the view, but the first time it tries to get its attributes, it returns a null HashMap (it gets drawn properly the following times).
Is there a way to make sure the item is in the table before trying to get its attributes?
Even putting the attribute retrieval into a while loop until it returns a not-null HashMap doesn't work so it doesn't look to be an issue of time.
You need to do Select or GetAttributes with ConsistentRead=true as Amazon SimpleDB supports two read consistency options: eventually consistent read and consistent read. Eventually consistent read is default. For more detail please refer doc. link
Try using AsynTask.
Add item to database in doInBackground.
Read it in postExecute.
You are done.