Android Room - emit single item update - android

I'm using Android Room to load data.
my query is this:
#Query("SELECT * FROM TrackedItem where isArchived = 0 ORDER BY creationDate DESC")
Flowable<List<TrackedItem>> getAll();
When calling getAll() I get all the items at the first time.
Then, I'm updating all the items using a network request.
What happens is that if I have 100 items, the getAll() will emit 100 times the entire list, which will update the RecyclerView 100 times.
Best practice for getting a single item that was changed and calling notifyItemChanged?
Thanks.

Answering my own question, if someone gets the same issue.
Instead of saving each item after an update, I save all of them once
calling #Insert with (TrackedItem... items).
which will only emits one update.

Related

Room DAO Update how best to handle old unwanted data

I have a Room table of objects and when I get my network call to refresh the list of objects the items could have been changed. So I need to remove any data that is no longer in the new fetched list.
Pre-Fetch Ids in Table:
|ObjectId|
|:-------|
|1|
|2|
|3|
|4|
Post-Fetch Ids in Table:
|ObjectId|
|:-------|
|1|
|2|
|4|
So Objects removed:
|ObjectId|
|:-------|
|3|
My Quesiton: Is the best way to do this just Delete all entries in the table before calling an #insert method or is there another way using the #update that will allow me to simply fetch the new data and remove all the old data that is no longer in the new list of objects? My understanding is that an #update will simply update objects 1,2 & 4 and leave 3 as it was.
As you have a list of id's (assuming these uniquely identify the rows) then you could update according to the list and delete (before or after the updates) according to the list using a WHERE clause that utilises NOT IN operator(s)
Note that the deletion should be done via an #Query not #Delete e.g. #QUERY("DELETE FROM the_table WHERE id NOT IN(:the_id_list);"
This would minimise the number of deletions. Deletiong and Updates should be done within a single transaction.

deleting records in sqllite is faster one by one or as a list

which is faster:
 
to delete records each one at a time
e.g. listOfObjects.forEach{ repository.delete(it.id) }
and here is the query
#Query("DELETE FROM myTable WHERE object_id=:id")
fun delete(objectId: Long)
2.    to delete the whole list in a single query
e.g. repository.delete(listOfObjectIds)
and here is the query
#Query("DELETE FROM myTable WHERE object_id=:id in(:objectIds)")
fun delete(ObjectIds: List<Long>)
?
By far, the second list version will outperform the first version, which issues N delete statements for a list of size N. The main reason is that the second version requires only one round trip to and from your SQLite database, while the first version requires N trips.
In addition, the second version has the added benefit that your entire logical delete operation can execute within a single transaction. The first version would, by default, execute across multiple transactions. This could lead to potential problems should, for example, an exception occur halfway through the batch of single delete operations.

ObjectBox: Get notified only when query with condition has changed items

Let's say I have a box of items, with some properties on them. I then want to receive only certain items, that match some condition, so I create an RxQuery like this:
val query = filesBox.query()
.equal(File_.completed, true)
.build()
RxQuery.observable(query).subscribe(...)
Now this query does indeed return all of the items that match that condition. However, when that table is updated, I always get a "notification" / onNext signal, even if the changed items do not match my query.
So if I have some files with completed = true and I add a new file with completed = false, the query will trigger, but return the same items as it did previously.
Is there a way around this? I know I could do distinctUntillChanged() as part of the Rx flow, but I want to hopefully find some way to do it with ObjectBox that's more efficient.

How to query Firebase database and not show values based of a boolean value

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:{
}
}

Sync SQLite database without causing multiple onChange

We store a copy of the server state of some items locally in our app. When we get new data from the server, items may have been changed, removed or inserted. When data is synced, all current data is fetched from the server.
Local list:
Item 1, progress 23
Item 2, progress 75
Item 3, progress 88
Remote list: (item 2 was removed)
Item 1, progress 55
Item 3, progress 88
Item 4, progress 1 (NEW)
The current solution clears the table and then bulk inserts all items like this:
// Remove old content (this is to prevent dead items being left)
mContentResolver.delete(URI_TO_TABLE, null, null);
// Insert all new items
// Most existing items are changed in a sync, hence we may just insert them again instead of updating
final ContentValues[] inserts = new ContentValues[newItems.size()];
for (int i = 0; i < newItems.size(); i++) {
inserts[i] = getChallengeContentValues(newItems.get(i));
}
mContentResolver.bulkInsert(URI_TO_TABLE, inserts);
The problem here is that we also use a ContentObserver, which sends out two onChange() each time (one for delete and one for bulkInsert), causing our UI to first update when the table is cleared, emptying our list of items, and directly after update with the freshly synced list, populating the view again. This is causing a lot of ugly blinking.
Is there anyway to just get one onChange()? The applyBatch() seems to generate one onChange() per operation. Can you somehow tell ContentProvider to threat a bunch of updates as only one?
OR is there another way of basically taking the new list (remote) and store it in the database?
As you mentioned applyBatch() is the right way to do this. Create ContentProviderOperation for each of your add/update/delete transactions, store them as an ArrayList<ContentProviderOperation> operations and run them as in a single applyBatch() operation.
http://developer.android.com/reference/android/content/ContentProvider.html#applyBatch%28java.util.ArrayList%3Candroid.content.ContentProviderOperation%3E%29
If your table is huge and you do not want to have the overhead of applyBatch() and need must use bulkInsert() then you could add some sort of hack like adding a extra in the delete query would would instruct the provider to not trigger notifyDataSetChanged()

Categories

Resources