Using multiple methods in a transaction - android

I'm making an Android app, which gets its information from XML files.
I'm filling the information in a database, for easier acces during the program's runtime, thanks to the power of queries.
However it came to my attention, that using Transactions greatly improves speed, so naturally, I want to use that.
My problem is the following tho;
In the idea of abstraction, after parsing all the information of one subject, the information gets send to the correct entity (class), and inside that entity there is a method that will add it in the database. After that, it returns to the parser which continues to read the next subject, which in it's turn will be send to right (and probably different) class again.
This is implemented with a switch statement, with every case pointing to a different class constructor.
If I want to use the speed of transactions, I would need to start a transaction already before the parsing, run through the parsing and query building (as far as I understand, all queries build within the transaction, are collected and in the end all executed as a bunch) and then end the transaction, once the whole file is parsed.
To make this a bit clearer, or faster to read; The code idea would be;
Class parser(){
database.beginTransaction();
try{
// start parsing in a whole different class, which also points to SQL queries (in different classes again) in the entitys with a switch
}catch(Exception e){
database.endTransaction();
}
database.endTransaction();
}
I hope i formulated my question clearly enough.
Kind regards,

Yes, you've got the general idea. However, you need to be careful to mark the transaction as successful when you finish parsing, and also to ensure the transaction is always closed even in the event of an exception.
Example from the docs:
db.beginTransaction();
try {
// do all the parsing in here
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Related

Atomically update multiple related tables

I am working with SQLite in Android. I have a model object that contains three lists, one of which is a list of lists. So I have five tables: A for the object, B for the list of lists, C for its lists, and D and E for the other two lists. The case that has me stumped is if the user is updating an existing object, and may or may not have made any changes to its lists. I think I will have to query each table B through E for records whose foreign keys match the primary key of the record I'm updating, and then loop through those results to see if I have a matching item in the lists, manually deleting/inserting/updating as necessary. But it seems to me like there should be a better way?
Related questions: If I wrap this whole operation in beginTransaction() and setTransactionSuccessful(), do I need to do anything else to ensure atomicity? I have never dealt directly with locks in my databases, do I need to add error checking to my existing queries to handle an event in which they are blocked? Is there any error case in which I would need to manually cancel the transaction, or will that occur automatically when I close my database connection?
Have a look on SQLite triggers here, This is exactly what you need.
If any error has occurred somewhere after beginTransaction(), then try to catch an exception and do not mark this transaction as successful. Without
setTransactionSuccessful() call your data wont be affected.

What is the best way to use threading on a sorting algorithm, that when completed, creates a new activity and gives its data to the new activity?

I will start this by saying that on iOS this algorithm takes, on average, <2 seconds to complete and given a simpler, more specific input that is the same between how I test it on iOS vs. Android it takes 0.09 seconds and 2.5 seconds respectively, and the Android version simply quits on me, no idea if that would be significantly longer. (The test data gives the sorting algorithm a relatively simple task)
More specifically, I have a HashMap (Using an NSMutableDictionary on iOS) that maps a unique key(Its a string of only integers called its course. For example: "12345") used to get specific sections under a course title. The hash map knows what course a specific section falls under because each section has a value "Course". Once they are retrieved these section objects are compared, to see if they can fit into a schedule together based on user input and their "timeBegin", "timeEnd", and "days" values.
For Example: If I asked for schedules with only the Course ABC1234(There are 50 different time slots or "sections" under that course title) and DEF5678(50 sections) it will iterate through the Hashmap to find every section that falls under those two courses. Then it will sort them into schedules of two classes each(one ABC1234 and one DEF5678) If no two courses have a conflict then a total of 2500(50*50) schedules are possible.
These "schedules" (Stored in ArrayLists since the number of user inputs varies from 1-8 and possible number of results varies from 1-100,000. The group of all schedules is a double ArrayList that looks like this ArrayList>. On iOS I use NSMutableArray) are then fed into the intent that is the next Activity. This Activity (Fragment techincally?) will be a pager that allows the user to scroll through the different combinations.
I copied the method of search and sort exactly as it is in iOS(This may not be the right thing to do since the languages and data structures may be fundamentally different) and it works correctly with small output but when it gets too large it can't handle it.
So is multithreading the answer? Should I use something other than a HashMap? Something other than ArrayLists? I only assume multithreading because the errors indicate that too much is being done on the main thread. I've also read that there is a limit to the size of data passed using Intents but I have no idea.
If I was unclear on anything feel free to ask for clarification. Also, I've been doing Android for ~2 weeks so I may completely off track but hopefully not, this is a fully functional and complete app in the iTunes Store already so I don't think I'm that far off. Thanks!
1) I think you should go with AsynTask of Android .The way it handle the View into `UI
threadandBackground threadfor operations (Like Sorting` ) is sufficient enough to help
you to get the Data Processed into Background thread And on Processing you can get the
Content on UI Thread.
Follow This ShorHand Example for This:
Example to Use Asyntask
2) Example(How to Proceed):
a) define your view into onPreExecute()
b) Do your Background Operation into doInBackground()
c) Get the Result into onPostExceute() and call the content for New Activty
Hope this could help...
I think it's better for you to use TreeMap instead of HashMap, which sorts data automatically everytime you mutate it. Therefore you won't have to sort your data before start another activity, you just pass it and that's all.
Also for using it you have to implement Comparable interface in your class which represents value of Map.
You can also read about TreeMap class there:
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html

Adding two relations via ParseRelation always sets the first class as target class

I am having a weird issue here.
The class Points I want to save data into, has two columns race and challenge which are relations to other classes with the same name.
I have asked this question on Parse.com forums as well
On the client side on Android, if I add the relation via pointsObject.put("race", raceObject), it throws an error saying that the type of "race" is Relation and I am providing a *Pointer
The iOS Counterpart of the app I am working on is completely able to save relations nicely - Happily Coded about 2 hours ago
When I use ParseRelation to add a one-to-many relationship, it takes only the first class as target class.
This code should explain:
ParseRelation<ParseObject> initiatorChallengeRelation = initiatorPoints.getRelation("Points");
initiatorChallengeRelation.add(challenge);
initiatorPoints.put("challenge", initiatorChallengeRelation);
ParseRelation<ParseObject> initiatorRaceRelation = initiatorPoints.getRelation("Points");
initiatorRaceRelation.add(race);
initiatorPoints.put("race", initiatorRaceRelation);
The first block of code sets the target class for the relation as "Challenge".
The second block tries to set the target class of the new ParseRelation object to "Race", but initiatorRaceRelation.add(race) is where it fails and throws an error : "IllegalArgumentException: Related object object must be of class Challenge, but Race was passed in."
I used Eclipse Debugger to check the data in the both Relation objects and found the thing about target classes being the same
Any help on where I might be going wrong?
I have been dealing with this issue since more than 12 hours and its really become a roadblock for me.
Any help would be deeply appreciated
Is Points a relation? From what you have mentioned, it seems so.
Assuming that initiatorPoints is a Points Object, you should get the challenge relation using
ParseRelation<ParseObject> initiatorChallengeRelation = initiatorPoints.getRelation("challenge"); //for challenge
then
initiatorChallengeRelation.add(challenge);
Similarly, for race
ParseRelation<ParseObject> initiatorRaceRelation = initiatorPoints.getRelation("race"); //for race
initiatorRaceRelation.add(race);
I think you need not even use initiatorPoints.put("challenge", initiatorChallengeRelation);
Once, you say
initiatorPoints.saveInBackground(callback), Parse updates the changes in the object by itself.
But do not forget to save the object once you have added the relation data. Hope this helps!

Android & SQLite - Occasional error 'unable to close due to unfinalised statements'

I seem to get the above error every so often in (an insert heavy) part of my code. I know normally this means there is an open Cursor within the connection but I have been through checking all my cursors are in try finally blocks and closed.
Also in logcat the error reads 'sqlite3_close(...) failed: 5 which I think means the database is busy?
The error can be 'ignored' if I add the following code to my finally block where the database connection is closed.
finally
{
writer.endTransaction();
boolean successAtClose = false;
while(successAtClose == false)
{
try
{
writer.close();
successAtClose = true;
}
catch(Exception e)
{
e.printStackTrace();
}
}
dbConn.releaseLock();
}
When stepping through the code above the 'e.printStackTrace()' is hit once but on the second attempt the 'writer.close()' does not throw an error.
Just to reiterate, this problem doesn't even happen every time the code block runs, the same data can be inserted say 5/6 times and only throw the error on one of these times. In addition the error does not reoccur straight away after happening once but continues to pop-up at random intervals.
Does anyone know why this might occur? Or a better way to recover from this than the finally code above? (Since it will take me a long time to add this to all my database code.)
ADDED:
Database is opened with a custom SQLiteOpenHelper which is extended to use a reentrant lock to ensure only one thread accesses the database at any one time. So the start of the code is like:
MyDatabaseHelper dbConn = MyDatabaseHelper.getDatabaseAccess(c);//await availability/lock the database here
SQLiteDatabase writer = dbConn.getWritableDatabase();
try
{
writer.beginTransaction();
//do inserts
writer.setTransactionSuccessful();
Get database access as follows:
public static MyDatabaseHelper getDatabaseAccess(Context c)
{
l.lock();
return new MyDatabaseHelper(c);
}
As a further test I have further added a Thread.sleep() call to the finally code (in my case of 12 seconds), before the close() but after the endTransaction(), that seems to have stopped the error and confirm it is not a case of an open cursor, but I would rather not rely on a timer. If there is a better way, perhaps to pre-check whether the database is busy, please share.
If you are using SQLiteStatement or SQLiteQuery objects to work with your database you need to make sure they get closed out as well. If it's SQLiteClosable you need to close it.
This mainly happens when you haven't closed the cursor, meant certain references to the database were invalid.
refer ths link Android SQLite Exception: unable to close due to unfinalised statements
The workaround is incorrect. close() decrements a reference counter and only when the counter hits exactly zero is the actual resource disposal i.e. sqlite3_close() attempted. On the second call the counter will be negative and the call will be a no-op.
You are correct that error code 5 is SQLITE_BUSY.
Now to address the actual problem, please provide some additional details, such as how you open and configure the database and how you begin your transactions.

How to over come database not opened exception?

I am implementing an app related to database.
So many times I am calling open and close database connection to insert, update and delete.
It is working fine.
But some times I am getting a database not opened exception in different situations.
How to solve these issues?
Well unless you put proper exception handling you would never know what causes this.
However a good idea is to adopt good ORM mapper for SQL Light with Android and this will improve your database interactions and exception handling and opening and closing it efficiently.
You can opt for SUGAR or ORMLight if you wish; In my opinion this should help you to fix your problem.
Based on the information you provided I can assume that the problem is in your business logic and nobody but you should be able to tell you the root cause.
Without your code here, we won't be able to point you to exact place.
One of the possible reasons can be that by your business logic you are trying to do some operation (insert, update whatever) on closed database.
You can do some workaround to try to ensure that your DB is always open when it is needed. If you implement database getter method with so called lazy initialization approach it will guarantee at least, that the DB is open when you need to access it.
Here is what I am talking about:
1. make a public method which supposed to return DB object:
public SQLiteDatabase getDB() {
if ((mDataBase == null) || (!mDataBase.isOpen())) {
// create or open your database using an OpenHelper
mDataBase = SQLiteOpenHelper.getWritableDatabase();
}
return mDataBase;
}
Now, everywhere in your code use this method to access the DB instead of directly accessing a variable mDataBase.
Note that the code is just to give you an idea and not actually compilable.
Still, I would recommend you to fix your business logic instead of using this workaround.

Categories

Resources