I am working on android ROOM + Kotlin (Just started)
I want to make a query which update the row of my table, but I am not able to find a definition on how to access the value from the parameter inside the query
#Query("UPDATE note_table SET description = :description, title= :title, priority = :priority WHERE id =:id")
fun updateNote(note : Notes)
I want to access the description from note object. like note.description how to do that inside the query !! Any help will good!
That is not possible, as docs specify
#Query("SELECT * FROM user WHERE age > :minAge")
When this query is processed at compile time, Room matches
the :minAge bind parameter with the minAge method parameter. Room
performs the match using the parameter names. If there is a mismatch,
an error occurs as your app compiles.
Other option is using Raw query, but that is needlessly complected for the use case.
Understand why Room doesn't allow object references
Mapping relationships from a database to the respective object model is a common practice and works very well on the server side. Even when the program loads fields as they're accessed, the server still performs well.
However, on the client side, this type of lazy loading isn't feasible because it usually occurs on the UI thread, and querying information on disk in the UI thread creates significant performance problems. The UI thread typically has about 16 ms to calculate and draw an activity's updated layout, so even if a query takes only 5 ms, it's still likely that your app will run out of time to draw the frame, causing noticeable visual glitches. The query could take even more time to complete if there's a separate transaction running in parallel, or if the device is running other disk-intensive tasks. If you don't use lazy loading, however, your app fetches more data than it needs, creating memory consumption problems.
Object-relational mappings usually leave this decision to developers so that they can do whatever is best for their app's use cases. Developers usually decide to share the model between their app and the UI. This solution doesn't scale well, however, because as the UI changes over time, the shared model creates problems that are difficult for developers to anticipate and debug.
from docs : https://developer.android.com/training/data-storage/room/referencing-data
Related
Recently kotlin flow is gaining a lot of attention. I have never done any reactive programming before so i thought now is a good time to learn it. Even though I have access to books and some articles I could not understand how to integrate it say on an existing app that does not have any rxjava. I tried looking for some sample but the only thing they would give me is very basic. Im really confuse about this reactive programming thing. For example, I have a list that I needed to get on database. Why would I use flow to get that data? If I visualize it as streams, that would give me one data each. While if I get that list I could get the whole list without waiting for each streams to come if I had use flow. I read a lot of articles about this kotlin flow, even rx java. But still, I wanted to understand why streams and how is it any different from other way like the example I just gave?
For example, I have a list that I needed to get on database. Why would I use flow to get that data?
Well, that depends entirely on what you are using to access that database and how it uses Flow.
Let's suppose that you are using Room from the Android Jetpack. In that case, you can use Kotlin coroutines in two ways, via suspend functions and via Flow:
#Query("SELECT * FROM stuff")
suspend fun getStuff(): List<Stuff>
#Query("SELECT * FROM stuff")
fun getStuffNowPlusChanges(): Flow<List<Stuff>>
In both cases, Room will do the database I/O on a background thread, and you can use coroutines to get the results on your desired thread (e.g., Android's main application thread). And initially, the results will be the same: you get a List<Stuff> representing the current contents of the stuff table.
The difference is what happens when the data changes.
In the case of the suspend function, you get just the one List<Stuff> from the point when you call the function. If you change the data in the stuff table, you would need to arrange to call that function again.
However, in the case of the Flow-returning function, if you change the data in the stuff table while you still have an observer of that Flow, the observer will get a fresh List<Stuff> automatically. You do not need to manually call some function again — Room handles that for you.
You will have to decide whether that particular feature is useful to you or not. And if you are using something else for database access, you will need to see if it supports Flow and how Flow is used.
I see that Firebase website has a lot of documentation to help us optimize the usage of resources, however, I have not found a detailed example of the resources used.
This could be useful to me to understand how to build my applications and to better choose the strategy in terms of performance and cost.
TAKING ANDROID AS EXAMPLE
I understand that when i do a:
query.addListenerForSingleValueEvent(...);
all the reference is "queried" to the database so that is a single query but takes down all the object.
if i do:
query.addValueEventListener(...);
the connection is kept open, but will it keep making connections on time intervals?
Or maybe is considered like a single connection in terms of billing?
And after a change on the database, will it query all the object down again?
In general how much is heavier and expensive to make a single request vs using the realtime-db feature of listening to a reference?
Maybe there is a section in the docs that explain this but I didn't found it.
query.addListenerForSingleValueEvent(...);
all the reference queried" to the database so that is a single
query but takes down all the object.
It will listen once to the objects within inside the child you are querying, not all of the objects inside the database.
query.addValueEventListener(...);
the connection is kept open, but will it keep making connections on
time intervals?
It has no intervals, instead it listens whenever a change is made into your database, lets say you change certain value from your database and that will trigger your addValueEventListener. This will only consume resources when some value changes into your database, so the usage will be a variant with your database usage, instead , addListenerForSingleValue will fire just once to query your data and we can assure that it will consume less network resources than a listener that is always listen to some changes to bring into your app
Check this usefull link : https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/ValueEventListener.html
I got two tables in my SQLite DB: entities and user_actions. Their approximate schemes:
The flow of the program is something like this (all DB accesses handled by ContentProvider):
The user performs some action which modifies one of the entities
The corresponding entity is updated in entities immediately. locally_modified value of this entity is set to 1
The information about user's action is stored in user_actions
At some point in future a sync session with the server is being initiated (I use SyncAdapter framework)
User's actions from user_actions are uploaded to the server one by one and removed from the DB in a background thread
When the uploading completed, I need to clear locally_modified flags in entities
At this point I encounter my atomicity issue: the synchronization with the server happens in a background thread, therefore the user can use the app and perform additional actions. As a consequence, right before I clear locally_modified flag for an entity, I must check that there are no records in user_actions corresponding to this entity. These three steps must be executed atomically for each entity having locally_modified set to 1:
Query user_actions for entries corresponding to entity's _id
Test whether the query from #1 returned an empty set
Clear locally_modified of that entity to 0
Given the above scenario, I have three questions:
Q1: Is there a way to lock SQLite DB accessed over ContentProvider in Android such that it can be accessed only by the locking thread?
Q2: If the answer to Q1 is positive, what happens if some other thread tries to access a locked DB? What precautions should I take to ensure reliable operation?
Q3: It is possible to execute atomic transactions with conditional logic using ContentProviderOperation? You can use "back-references" as described in this answer and this blog post to reference the result of a previous operations, but is there a way to use that result in some kind of if-else statement?
Thanks
Is there a way to lock SQLite DB in Android such that it can be accessed only by the locking thread?
Yes, have a look at SQLiteDatabase.beginTransaction() (source). I believe you need SQLite's exclusive transactions, but you need to study that a bit more for your exact usage.
If the answer to Q1 is positive, what happens if some other thread tries to access a locked DB? What precautions should I take to ensure reliable operation?
There's an SQLite.amIInTransaction() method that you could check, or just catch an SQLiteDatabaseLockedException (more SQLite exceptions that you should look up)
It is possible to execute atomic transactions with conditional logic using ContentProviderOperation? You can use "back-references" as described in this answer and this blog post to reference the result of a previous operations, but is there a way to use that result in some kind of if-else statement?
Never done that, but it seems that overriding ContentProvider's applyBatch and wrapping it in a transaction should work:
Android: SQLite transactions when using ContentResolver
The answer turned out to be pretty simple, but it is kind of a "hack" - just add additional Uri to ContentProvider.
For example: initially my ContentProvider supported the following URIs:
Uri.withAppendedPath(MyContract.CONTENT_URI, "entities")
Uri.withAppendedPath(MyContract.CONTENT_URI, "user_actions")
In order to support the atomic operation described in the question I added an additional Uri:
Uri.withAppendedPath(MyContract.CONTENT_URI, "clear_modified_flag")
When this Uri is updated through:
getContentResolver().update(
MyContract.ClearModifiedFlag.CONTENT_URI,
new ContentValues(),
null,
null);
my ContentProvider executes an SQLite transaction that locks the database for the duration of the operation and rolls it back in case of any errors (as described in this answer).
That's it.
P.S. my ContentProvider is not exported (i.e. other apps can't access and use it), therefore it is safe to add this new Uri to it. But keep in mind that if you do export your ContentProvider, then exposing functionality like this one could be problematic.
I am creating a Hotel Booking System for the Android application.
I was thinking about how to implement a safe way to insert a booking into my database. The request will be sent from the app to the MySQL database (which is hosted on a web server) via my web service.
When I create a booking I insert the: CustomerID, HotelID, RoomID (via a nested select statement to find an available room), checkInDate and checkOutDate.
However, how can I ensure that two different people won't book the same/last room if they both hit 'book now' at roughly the same time. I thought about using Synchornisedfor the java method but will that make any difference if a range of different users on different mobiles try to make a booking?
What you are looking for is transactions.
Using transactions you will be able to isolate access to a given set of records into a single, atomic logical entity. Any operation of a certain complexity affects multiple rows, columns and even tables, or needs multiple (atomic or non-atomic) statements to complete. A transaction is a mechanism to ensure logical consistency of your data even if any of these operations fails. In that case, the incomplete transaction is rolled back, otherwise the transaction is committed.
And these are exactly the both possible outcomes with transactions: commit or rollback. In pseudo code it looks like this:
begin transaction
try {
required operations to reserve a room for a given time frame
if( success)
commit transaction
else
rollback transaction
} catch {
rollback transaction
}
Synchronizing in Java is certainly possible, but it has several major drawbacks:
it prevents you from scaling the application, because it affects only the current process.
it also prevents you from extending the solution, e.g. by sharing the data with associated programs
a database transaction is designed to handle crashes without producing inconsistent data
I don't think that you're asking about threading as much as avoiding a race condition.
Not knowing anything about your architecture, one way to avoid such a race is to set a timestamp when each user hits the 'book now' button and pass it as a field in the transaction. The application server would then sort all the entries in its queue according to the timestamp, as opposed to simply accepting them in the order they arrive.
You need to create a unique key {room number, date} such that a room can only have one booking per date. Then a client booking becomes an insert of as many rows as there are days in the booking, carried out within a transaction.
Threads really have little to do with it.
In my Android app, I need to get 50,000 database entries (text) and compare them with a value when the activity starts (in onCreate()). I am doing this with the simplest way: I get the whole table from db to a cursor. However this way is too laggy. Are there any other ways to do it more effectively ?
Edit: The app is "scrabble solver" that is why I am not using WHERE clause in my query (Take the whole data and compare it with combination of the input letters). At first I was using a big table which contains whole possible words. Now I am using 26 tables. This reduced the lag and I am making database calls on a thread - that solved a lot problems too. It is still little bit laggy but much better.
To summarize and add a bit more
Let the database do the work of searching for you, use a WHERE clause when you perform a query!
If your where clause does not operate on the primary key column or a unique column you should create an index for that column. Here is some info on how to do that: http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html#indexes
Google says: "Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes."
Run the query analysis using EXPLAIN QUERY PLAN http://www.sqlite.org/lang_explain.html and look for any scan operations, these are much slower than search operations. Uses indexes to avoid scan operations.
Don't perform any time consuming tasks in onCreate(), always use an AsyncTask, a Handler running on a background thread or some other non-main thread.
If you need to do full text search please read: http://www.sqlite.org/fts3.html
You should never read from the database in the UI thread. Use a background thread via AsyncTask or using regular threading. This will fix the UI lag issue your having.
Making the database read faster will help with bringing the data faster to the user but it's even more important that the fetching of the data does not block the user from using the app.
Check out the Following Links:
Painless Threading in Android
YouTube: Writing Zippy Android Apps
Use a WHERE clause in your SQL rather than reading the whole thing in. Then add an index on the columns in the WHERE clause.
At least you can put index on the field you compare and use WHERE clause. If you are comparing numerics Sqlite (db engine used by Android) supports functions such as MIN and MAX. Also if you are comparing partial strings you can use LIKE. For query optimization there are many resources such as this