Android - How to use transactions when modifying database via ContentProvider? - android

When a user taps their NFC tag, my app:
Inserts a new user into the users table, getting back the user _id, then
Writes this _id value to the user's NFC tag.
The problem is that if that user moves their tag away too quickly, step 2 will fail with an IOException. The user will then have to tap their tag again, but this will result in step 1 being repeated - i.e., duplicate entries. :-/
To overcome this issue, I would like to use transactions based on this example code from the API documentation:
db.beginTransaction();
try {
// Insert data into database, getting back _id
// Write _id to NFC tag
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
...but my database is wrapped in a MyContentProvider, so I don't have access to db.
Is there a way to use transactions when inserting data without abandoning the usage of the MyContentProvider?

You could reverse the operations: you could query your database for the next available ID, write the ID to the NFC tag, then update the database with that ID if you were successful in updating the NFC tag.

Related

How to manage data in an offline Android app in kotlin?

I want to make an android app that works offline. For the data part, I want to have some data in a json file, and whenever my app is open firstly that JSON file is fetched, and from the fetched data I want to make tables entries in android room database(offline). So that, let say if user liked some quotes, then i can change the state of that quote as liked in room db, and when user clicked on Liked Quotes navigation, I can show those offline stored quotes which were liked (OfCourse when user delete the app that data will be lost). The problem I'm facing is where to fetch that data file and create entries in room db. If I do this in onCreate() then whenever user will open this app the duplicate entries will be created everytime. How to make those entries only ones?
There's several ways to do it. One way is to include a random UUID in each element, and make that column in the DB have a UNIQUE constraint. Then re-adding it will fail (alternatively you can use an UPSERT and then it will automatically update the data in case the data changed).
Another way is to just not process the file if it already exists in onCreate. Your logic can be
if(network_exists) {
copy_file_from_network()
}
else if(json file exists) {
return
}
else {
copy_file_from_assets()
}
process_json_file()
Actually I can see a good argument for doing both- that way if there are updates to existing rows you process them, but if there's no new data you don't waste your time.
As for a good place to put this- I'd be running this during your splash screen if you have one, so the user has an indication that you may be processing for a while.

SQLite in Android - How to generate User IDs with date and sequential number per day

I currently have an app where I store user data in a SQLite database, and one of my fields is a User ID. I would like to add an option to auto-generate User IDs in an mmddyyXXX format, where XXX is a sequential number per user that resets every day.
Does anyone know how I would approach this? I looked at some of the other similar questions, but they don't seem to be helpful.
This is not complicated at all. If your'e similar with SQLite in android just take the date and the userId using a SELECT and generate that string yourself.
If the XXX is not the userId just save another table containing 'tokens' for users. every userId would have a 'token'.
Every new day just change the contents of this table.
I believe you could use a TRIGGER that will generate the userid when a row is inserted.
The following may suit :-
CREATE TRIGGER IF NOT EXISTS newuserid AFTER INSERT ON users
BEGIN
UPDATE users SET userid = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)||
(
SELECT CAST(substr('000',1,3-length(count()+1)) AS TEXT)||CAST((count()+1) AS TEXT)
FROM USERS
WHERE substr(userid,1,6) = strftime('%m%d',date('now'))||substr(strftime('%Y',date('now')),3)
)
WHERE userid IS NULL;
END;
The trigger is named newuserid
userid is the column for the auto-generated id. The above relies upon it being NULL so it cannot be a PRIMARY INDEX.
There is no reliance upon other columns.
Testing
Starting with an empty table :-
Inserting 4 rows using INSERT INTO users VALUES(null,'This is a new user'); results in :-
To check for another date the rows are adjusted from 041018??? to 040918??? as per :-
4 more rows are inserted using INSERT INTO users VALUES(null,'This is a new user');, resulting in :-
Note this answer isn't intended to be fail-safe but rather the basis of the concept for the answer.

How to execute java code when an SQLite trigger is fired in Android app

In my database I have three tables (A,B,C) in which table A has foreign keys into both B and C. When I delete from either B or C, I want to also delete the row in A if BOTH foreign keys are null, and I have a constraint placed on the foreign keys that sets them to null if the B or C table deletes that key. I have two triggers on tables B and C to delete a row from A when appropriate and this seems to be working okay.
The trouble I'm having is there is a file name stored in table A that I want to delete but I can't if I set up triggers to handle my situation. So is there any way to know when a trigger is fired? Do I have to manually execute the logic for my trigger so I can delete the file too?
tl;dr: How can I execute some java code when a trigger is fired in my applications sqlite database?
SQLite itself has user-defined functions, but the Android database API does not allow you to access them.
You have to do the checks in your code whenever you have issued such a DELETE statement.
Best way to do this I found is to return the rowID.
long newRowId;
newRowId = db.insert(tableName,primaryKey,values); (insert or delete or whatever)
If that trigger fires you will get a row id of -1. Then just show your message or run your query where you delete something else when you get a row id of -1

Update the database table with the same button that is used to insert

I have a really different situation. I have a form where user fills the data and insert into database. Now in the same form, I need to update his data also. Something like, there is a search user autocomplete text view. When user finds him then the data from database directly fills all the form fields. Now, either he submits data with the same info, if his info has not changed or, if the info has changed, he changes only some of the fields and then press the same button(submit) to update his data. I am doing so because I need to register the user in different particular session. He can register many times with same data. But when his some of the data is changed, I need to update his data but with registering him in the session with new id.
I do not want to provide you my codes here, I just need some technical help, how can I achieve the solution of this problem? If I am not wrong, I am thinking to use TextWatcher. I can implement textwatcher in each edittext form. When the text is changed, somehow the button(submit) that is used to insert get some connection with textwatcher, that it should update the database instead insert.
I am not sure if I am right. Help me please if you have some easy and reliable method to do. Thanks!!
You must have created a method in the Activity or a method in a separate class(I would prefer a separate class for database related methods). And you must keep some registration id or something which should match every time.
Suppose the registration id is named as ID. When you are inserting the data check within that insert method whether this ID matches with any previous records or not. If it matches then do update instead of insert.
Something like:
SQLiteDatabase objSqliteDB = DatabaseHelper.openDataBase();
objSqliteDB.beginTransaction();
SQLiteStatement stmtRecCount = objSqliteDB.compileStatement("select count(*) from ID where ID =?");
stmtRecCount.bindString(1, ID);
long count = stmtRecCount.simpleQueryForLong();
if(count != 0)
{
stmtUpdate.bindString(1, Name);
. . .
stmtUpdate.execute();
}
else
{
stmtInsert.bindString(1, Name);
. . .
stmtInsert.executeInsert();
}
Add whatever other fields you need to update
stmtInsert
&
stmtUpdate
will be yourinsert and update query

Update SQLite table of Android application optimally

I am working on an android application using android:minSdkVersion="14". The application receives data as JSON from a server. The data received need to be added to an sqlite table. If a row exists, all fields except for two have to be updated. If a row does not already exist in the table, it has to be inserted. I am looking for the most efficient way as regards performance.
The function insertwithonCoflict() has been considered but it is not an option since in case of update, it updates all the fields including the two that should not be updated.
The function replace() is also not suitable.
I would opt for a SELECT to check if the row exists and then an INSERT or UPDATE but I was wondering if I could optimize the procedure somehow .
Two approaches:
Change the database structure so that the table has only the server data. Put local data (the two columns) in another table that references the server data table. When updating, just insert to the server data table with "replace" conflict resolution.
Do the select-insert/update logic.
For performance in any case, use database transactions to reduce I/O. That is, wrap the database update loop in a transaction and only commit it when you've done with everything. (In case the transaction becomes too large, split the loop into transaction chunks of maybe a few thousand rows.)
A nice solution I use is as follows:
long id = db.insertWithOnConflict(TABLE, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
if(id!=-1) db.update(TABLE, contentValues, "_id=?", new String[]{String.valueOf(id)});
This ensures the row exists and has the latest values.

Categories

Resources