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.
Related
I want to iterate through a list of data and populate a table with preset rows.
The naming convention is r#t1 where r# is the row number and t1 is the text field number - r# is the only thing that changes, incrementing through the rows of the table.
I can not seem to get this to work, I know you can do it through findViewById<EditText>(resources.getIdentifier("r${i+1}t1")), but I am wondering if it can be done with binding as well as it is much cleaner.
Here is some code of what I have tried:
for(i in 0..data.size-1){
binding."r${i+1}t1".text = data[i].name //how I want it to work
}
binding.r1t1.text = data[0].name // how I currently have to go about it.
binding.r2t1.text = data[1].name
...
Any suggestions would be awesome.
I am trying to make blocks of data (10 each) as query.
The limitToLast() and limitToFirst() work without each other but crashes the app when together.
query = db_reference_type.limitToLast((int) (long_total_buildings - (long_list_page * 10))).limitToFirst(10);
With long_list_page = 0 and long_total_buildings = 10
query = db_reference_type.limitToLast(10).limitToFirst(10);
The app just crashes when the program gets to that line.
There is no way to combine limitToFirst() and limitToLast() in a single query. You seem to be building a pagination system, and looking for an offset() condition, which doesn't exist in Firebase.
It's easier to understand what is possible once you know how Firebase processes your request.
When it receives a query at a location, Firebase retrieves an index of the items on that location on the property that you order the query on (or on the key if no order is specified).
It then finds the value that you've indicated you want to start returning items from. So this is a value of the property that you order the query on (or on the key if no order is specified).
It then finds the value that you've indicated you want to end returning items at. This too is a value of the property that you order the query on (or on the key if no order is specified).
So at this point the database has a range of values in the index, and by association the keys of the items matching those values.
It then clips the items in the range by either the number of items from the start (if you use limitToFirst()) or from the end (if you use limitToLast).
And then finally it returns the remaining items that match all criteria.
Note that the value you pass to limitToFirst/limitToLast is only used in the last step of this process. It is not used in step 3, which is what you seem to be trying.
I am using liveData in my application. I do a DB Query which returns a LiveData<PagedList<Contact>> of contacts stored in DB.
I want to modify this livedata before giving it to observers. Suppose there are ten contacts in the LiveData list, i want to do some comparison with another list and set which contacts are primary in the LiveData list.
After doing this i want to give it to observers .
e.g -
val allContacts: LiveData<PagedList<Contact>> = getFromDB()
val list: ArrayList<String>() = list of some primary contacts
traverse allContacts and list and set which values in allContacts match the values in list.
which ever values in allContacts match, their isPrimary property will be set to true.
Now after modifying allContacts, i want to submit it to observers like:
allContacts.observe(this, Observer(adapter::submitList))
I tried LiveData.transform, But not able to use it properly.Can anyone suggest me how to achieve it using transform method or some other way.
What you are looking for is a Transformation. Use Transformations.map() to create a new LiveData from a function that will be run everytime the first LiveData changes.
e.g.
val allContacts: LiveData<PagedList<Contact>> = getFromDB()
val contactViewModel = Transformations.map(allContacts, {
// Transform and create new list from old
})
Your problem is rooted in the fact that you wish to "intercept" the updates that will be posted to the LiveData object by the DB. Regardless if this is a good approach you can technically achieve it by wrapping the LiveData that is returned by the DB with your own subclass of LiveData.
In other words. UI --observes--> YourLiveData --observes--> DBLiveData
P.S. I think genrally speaking you could solve your problem by modifying your DB query, but that is just me assuming you already have "primary contacts" in some other table
I am trying to make a notes taking app and the way I wrote app to delete specific row is in this way -
FIRST - If a user taps on any cardView from a recyclerView, first activity will forwards cardView position using getAdapterPosition().
SECOND - Second activity receives cardView`s positon, to delete a specific row from SQLite database, I called a method known as 'totalNotes()' which will return total number of rows present in SQLite database. Finally, to delete the row I subtract the number received from 'totalNotes()' method with the getAdapterPosition().
PROBLEM - They way I have programmed it only works if the rows in the database are in sequential order. However, when a user wants to delete a row number 3 and 2 from 5 rows, the remaning rows are 1,4 and 5. How can make the database so auto implement sequential order after row deletion?
I have looked on 'almost' similar problem on the site but they fail when I try to implement in my code. I am new to Android development.
[Demo Picture][2]
How can I assign sequential IDs?
How my app looks like
You should not base on the row number sequential. Almost(if not all) all databases have the same behavior on auto-increment field. When you get data from database you need to get also the ID, and to keep the ID inside the APP so when deleting from DB you will delete base on that ID:
id = note.noteID; /// Selected note (noteID) to be deleted.
--------
dbHandler!!.deleteNote(id);
---------
// Here you bind your note to your viewHolder
fun bindItems(note: UserNotes) {
noteTitle.text = note.noteTitle
noteText.text = note.noteText
noteText.noteId = note.noteID;
}
Using sequential Ids is bad, because when you delete a record with Id = 5, the next record you add to your table is not going to be Id = 5 as well, it's going to be Id = 6, so it's going to cause you problems sooner or later.
The way #Simion suggested is:
You ask for all the data, (i.e. all your notes)
When you select a note you ask for the Id of that note, and save it in a variable.
If the user decides to delete that note you should do deleteNote(noteId), that way you can use anything you want as an Id and you don't rely on the Ids being sequential (which is, as I said before, usually a bad idea)
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()