SQLiteConstraintException Best Practices for Android - android

I have a pretty broad question and mainly want some advice and best practices for this Sqlite Exception and how to handle it. I am catching it no problem, just needing help with handling it. In my app, I have only one field for my database that is labeled unique for this reason, as I do not want this one particular value to be duplicated in the database. I am using the method insertWithOnConflict() but am wondering what is the best constant to set for the conflictAlgorithm parameter. I have read up on all of them that are available from the SQLiteDatabase|Android reference page and am still not sure which would be my best bet. I would ideally prefer to accomplish this:
Prompt the user immediately with either an AlertDialogueBuilder or Toast message that the value they have entered, is already contained in the database and they need to alter this current value before continuing. Since this unique field is one of the first one's out of all 15 of them, I would even be fine with writing and committing the current transaction with all the other data collected for the other remaining fields and just labeling that unique field with a message indicating a default "Needs Unique" value or something but this would be last resort. At this point, when the exception is caught, my app does not crash, it just does not commit the write, and returns to the previous calling Activity, which is a listView of all previously collected assets in the database. Would it be wise to just go ahead and relaunch the Activity where the data collection takes place, prompting them about the duplicate key at that time? Or stop the transaction from attempting to be committed and not written before the app is sent back to the calling Activity? I just can't seem to do anything with the exception once it happens. Any advice or tips would be greatly appreciated. Whatever are the best practices for working with data and databases I would like to know and learn for the future. Thank you all.

Related

Ideal way to tackle pending data changes (when to save changes)?

I have a rather peculiar case on my hands, and Im surprised that noone seems to have written about it/something similar for Android (or my Google skills suck)
Situation #1:
User can input text into field1 and field2.
User can also re-arrange items in a list (displayed in a RecyclerView)
Whenever the user does any of the edits, the UI is already showing the updated data (e.g. editing field1 will show the text as the user types it, and the list of items will show them in the new order as the user re-arranges them).
Saving the data right away here will trigger the UI to refresh (to display the same thing) and give the user a bad experience (field1 focus will shift to the first letter, and the app might crash if the user quickly re-arranges list items).
So it makes sense to store the edits and execute them at a later point.
Situation #2:
User can tap plus/minus buttons to increase/decrease a value
User can input text into field3.
As in situation #1 above, editing the field will already have the UI in the updated state. But, in this case - tapping the plus/minus button will also update the data, but the UI will not be updated (unless the data is saved, and the query ran again...).
Problem:
If data is saved immediately as the user performs an edit, besides doing a lot of saves, it makes for a bad user experience as the UI will refresh in some cases whereas its already up to date.
If the edits are tucked away and performed at a later point, the UI wont refresh.
Im using MVVM, so all performed actions are sent to the viewmodel and it decides what to do. I find myself looking for a solution that works differently across different screens of the app, but I know that would just be shooting myself in the foot and then jumping off a bridge. Surely, there must be someone out there that has come across this challenge and had some insights around it?
Ideal solution: One solution that just works for all the different screens. Do you have it? Please let me know.
/ Desperate Android Dev
First of all, let me start by stating that I don't think there is a correct answer here, but you should consider what your own app does and then determine what you need to do.
Let me explain. Consider two application, one that saves TODO items and the other is a banking application.
I will now explain what I think could work for your application, since you have not mentioned explicitly any requirements that contradicts that.
In situations like that, I believe being optimistic is a good idea. Assuming that things will not fail, and when they do, try to back out. What does that mean?
That means, for example, in the scenario you mentioned, user enters something in a field. You should let the UI update automatically (Nothing we do here, that's just Android), when that happens you save those changes either locally, or to a server, doesn't matter.
Of course, you can optimize, instead of saving each letter, throttle the input somehow, but you get the idea.
This can either be a succeed or a failure, because we are optimistic, we let the UI update and the user get the feel that our application is lighting fast. You don't need to reload anything, or refresh anything. The UI should match your Model state now already.
What if the things go south, and your HTTP request or DB update fails for some reason, then you need to take action. But try to keep your reaction appropriate.
You can handle that failure in so many ways, again, depending on how critical what you are doing in your app really is.
You can just show a Toast, or even do nothing if the user action was so trivial.
You can show the user something a bit more concrete if the action is of some significance, maybe a Snakbar with retry and explanation of what happened.
You kill your process and finish all activities -kidding don't ever do that- but showing a very intrusive pop-up and possibly reverting the UI value to the correct one, if what the user was doing is quite critical.
Now this approach doesn't just give the feel that the app is really fast, but it also keeps things simple.
Another advise is don't try to solve problems that don't exist yet, that means don't start implementing background services and job queues for some local persistence jobs that never outlive a view, and could never will.
Instead, use measurements, log those errors and failures with some tool, and use those stats to know what needs to be fixed -if any-
Back to our two applications, this approach might be perfect for a TODO app, however this might not be too good for a banking app.
Assume the user transfers money, we say immediately, ALL GOOD MATE! and then the request fails and your user's landlord kicks him out for never paying rent.
So it all comes to how sensitive the operations your're doing.

How to make SQL insert safely?

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.

Mobile devices offline sync with webservice

Im am developing a webservice for an App that I am writing. I want to make the App offline accessible.
I made that webservice so that if you request JSON from the webservice you can give a date:
/color/colors/date/2014-03-01T12:00/
If you don't give the date you will get everything that is inside the database and that is active. If you give the date you will only get everything that is updated after that date.
Now my problem is that if I remove something from the webservice of from the App then it will not be synced and the other devices will never know that it is removed.
I could work with a field where I say that a record is removed but then I need to keep every record and I can't delete any record.
Is there a better way to do the syncing? Or what is the best way?
I think there is no possible way to detect the deleted entry's change, unless you send the information that the entry is deleted. The best practise you set a field in the table with integer type, then you can set this value on updates. You don't have to set it only 1 or 0, you can use bigger numbers (for example I used 30 on that entries, that I deleted on 20th march , on this day was a big code logic change. after that i knew when the status integer is 30, then i deleted this row after that date.) It may be a silly example, but you can implement your own logic.
It depends on how important it is to update the rest of the devices when a change is made.
If it is critical, then it would be worth implementing push notifications or something similar to each device to let them know about the updated situation. Otherwise, you would simply have the other devices poll the server to check for changes on their own accord, and the frequency or the trigger of this poll would depend again on how critical it was that they get an update. Maybes they only need updating when they visit a certain activity, so in that case you would only poll when you reach the onResume() event of that activity
Update
If you don't need to keep a history of the deleted record, then why can't you just delete it, and then when the rest of the devices update, you clear all and download a fresh set? If that is too intensive, you would NEED to have a reference to the id, which you could do in a table or use a special value in the field (like null, 0 or -1) to mark it. Otherwise there would be no way to reference it

Android. Shared Preferences. Corrupted data retrieved in case of crash

This is more of a request for your opinion in something, rather than a question. It will be kinda long, so no worries if you don't have the patience to read it all. Stop here if you don't :)
I am currently using Shared Preferences to frequently store some values, one by one, during the execution of my app. In fact, every 2 seconds the values change and they need to be stored in the preferences so the user, after closing the app and reopening it, can continue from where he left off.
A problem which I've thought of is that if by any chance the app is closed forcefully, for example the battery dies WHILE the values are being saved, then when the user tries to resume from where he left off, the data won't be valid, as it wasn't previously entirely saved.(for example just 2 out of 5 values managed to be stored).
How i thought to overcome this problem is to save the data twice, in "TWO SLOTS" (what i mean by slot is each value, like I've said there are multiple values, will be stored in either "valueName_1" or "valueName_2"), and alongside the normal values stores, i'll also save two values inside the preferences which will be used to validate if the data was entirely saved or not.
One of these two values curSavingSpot will refer to the position in one of those two slots where I've LAST saved (or have TRIED to save in case of fail) the values, and the other curSavedSuccessfully will keep track if the LAST stored values were ALL stores successfully.
For example:
initially every field in the Shared Pref is null. curSavingSpot points to 1 (the first "slot") and curSavedSuccessfully is false.
i start saving the values in slot 1 and finish saving them without any interruptions, so curSavedSuccessfully will be made true as we have successfully saved all values
after 2 seconds, i start saving the new values. This time in slot 2. But first, i set the curSavingSpot value to 2 AND curSavedSuccessfully to false. Let's say when i save 3 out of 5 values (got 2 more to go), the device crashes. When i reboot it, i'll first check to see if the last saving session finished successfully, according to curSavedSuccessfully that didn't happen, so i look at curSavingSpot and take the opposite value, in this case i know 2 hasn't finished successfully, so it means 1 has correct values.
What do you think? Is this a good way to do this? Is there a better way to make sure it has saved all the required values?
Any suggestions? Are there any flaws with this idea?
Sorry for the long post.
Honestly it sounds to me like you are overthinking it. The commit() and apply() methods of SharedPreferences claim to be atomic, this means either all the changes to SharedPreferences happen or none of them do. As long as you are not calling commit() more than once (after you have made all your changes) you should be fine. Basically your scenario where you can commit only some of the preferences will never happen. If your values are invalid when commited individually, it makes no sense to commit them one by one, just commit them when they are all ready to be commited.
You could also use a DB if you want to audit your commits (and always just pick the one with the last timestamp). SQLite has atomic commits, and you can read more about what an atomic commit means here and why it never writes just part of a row.
I would suggest that you use the "Internal Storage" for some kind of backup. I assume its a bit slower than the "shared preferences" but the internal storage is made for storing data at a larger quantity, and shared preferences is, as the name states, for preferences (finite set of information, not changing frequently).
So: I would use the internal storage to store the values of the app every minute or so, and the shared preferences for the small, incremental steps between. With this you can even provide a further backup than just one step.
And probably users don't kill their running apps just because, so I think it's a rather rare that your app gets killed. And for everything else there is onDestroy() where you can save all your stuff.
cheers!

How to determine which row in contacts database has been updated

I am writing a backup application and need to know which records in the contacts database have been updated, so that I can backup only those records. I have looked at the documentation and it seems that there is a "DIRTY" constant field in ContactsContract.RawContacts class, which is supposed to be set to "1", for the rows that are updated. But it is not clear to me as to when will this field get cleared to "0". Can someone provide me example code on how to use this? Can this field be used to determine if a contact has been added or updated?
If this is not the correct way to achieve what I am trying to do can anyone suggest me another way. I am also aware that I can use the RegisterContentObserver() call to identify whenever there is a change in the Contacts database but this will require my application to be running always in the background, which is way too expensive and I do not want to do that.
If there is anyway to extract the timestamp when the various contacts have been added or updated that would be perfect too, but I cannot find how to do that.
Any help is very much appreciated.
I have looked at the documentation and it seems that there is a "DIRTY" constant field in ContactsContract.RawContacts class, which is supposed to be set to "1", for the rows that are updated. But it is not clear to me as to when will this field get cleared to "0".
In my experience, whenever there is a 'dirty' indicator of some sort, it is the responsibility of the backup/sync app to reset it once the data has been successfully committed during a backup/sync operation.
This can cause problems, however, when more than one application is used - the first one run at any time after data has been updated will reset the flag and the next one run wont find anything to backup/sync.
In this case if you require that a user is able to use a 'sync' app (for example) but you also want to have a 'backup' operation then registering a ContentObserver would serve a better purpose and there's no reason why this should be 'expensive' on resources if implemented correctly.
EDIT: Although there is no 'timestamp' there is a 'VERSION' field which is updated (which is when 'DIRTY' is set). If you backup this field, you could simply leave the 'DIRTY' flag set and compare current VERSION in the contacts DB with your most recent backup.

Categories

Resources