Managing Android ORMLite Concurrency and Overwriting - android

I'm trying to solve a (hypothetical) concurrency problem in my Android app that uses ORMLite for the database management.
In particular, I have a ContentService class that manages the database, here's some code (simplified to understand the problem):
public ContentManagerImpl(Context context) {
mContext = context;
configure();
// Once configured, get the DatabaseHelper
DatabaseManager.configure(context);
}
private void configure() {
// If needed, unzip a folder with an sqlite file
// representing the database and saves it on device
}
#Override
public void checkForUpdate() {
// Checks if new database version is available
new CheckForUpdateTask(CheckForUpdateTask.CheckForUpdateCallback() {
#Override
public void onCheckForUpdateFinished(boolean updateNeeded) {
if (updateNeeded) {
update();
}
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
#Override
public void update() {
// Downloads the new database zip, unzip the folder and sava an sqlite file
// representing the database
new UpdateTask(mContext, mMetaData, new UpdateTask.UpdateCallback() {
#Override
public void onUpdateFinished() {
DatabaseManager.refresh();
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
This class is created in the onCreate method of my Android Application class.
Since in the app I have only one Activity, the checkForUpdate method is called every time the onResume of that activity is called.
The problem is, sometimes when there's an update needed and the app is resumed (or even when first launched) I get an exception on a database query performed inside the DatabaseManager.configure() and DatabaseManager.refresh() methods.
That's because I try to get the first element of a single-row table but the query returns an empty list. It seems that the database is not ready, or that someone is still writing on it. I've also tried some lock mechanism but without luck.
So, since is the main (UI) thread that overwrites the database file, my questions are:
Can it be a problem to access the database from multiple threads/tasks?
Can I perform database queries on a separated thread if I write the db file on the UI thread?
Thank you all for your support.

Related

Load data from Parse.com and save in Local Data

I don't understand how is the Parse working?
I download data in parse to my arraylist , but when I show the Pets.size inside (//here) method "done" it will show 4, but when I show pets.size outside the done's method it will show 0?
public class Test extends AppCompatActivity {
ArrayList<Pet> pets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
pets = new ArrayList<>();
ParseQuery<Pet> query = new ParseQuery<>("Pets");
query.findInBackground(new FindCallback<Pet>() {
#Override
public void done(List<Pet> list, ParseException e) {
if (e!=null){
Toast.makeText(Test.this,"Error",Toast.LENGTH_LONG).show();
}
for (Pet pet : list){
Pet newPet = new Pet();
newPet.setName(pet.getName());
newPet.setType(pet.getType());
pets.add(newPet);
}
// here
}
});
Toast.makeText(Test.this,"You have "+pets.size()+" pets",Toast.LENGTH_LONG).show();
}
Here's my Pet class:
#ParseClassName("Pets")
public class Pet extends ParseObject {
public String getName(){
return getString("name");
}
public void setName(String name) {
put("name", name);
}
public String getType(){
return getString("type");
}
public void setType(String type) {
put("type", type);
}
}
And an orther question , what should I do if I wanna save the data in local data?
Explanation:
findInbackground performs an operation to find all ParseObjects in a background thread (outside the main thread, or UI thread). So when it completes in the place where you have the comment
//here
That is when the background thread finishes it's call to find the objects. When you try to look at the size of the array outside that call where it shows size of 0, it is because it reached that point before the background thread finishes it's work (of adding to your array from objects it found).
What is happening is the operation for find() is happening in parallel with your main threads code.
And for your second question, make sure you enableLocalDatastore and then you can pin results from queries to your local cache. This data is stored on the device until the user deletes your app or clears cached data in settings.
Follow this guide to setup local cache Local Datastore with Parse
Note: A solution to your problem for when the background task of finding the pets is complete is to call a method from within the Callback for the findInBackground call that will handle the newly found Pet ParseObjects. Also remember to handle if the query fails either by finding no objects or some failure in connection / timeout.
just calling pet.pin() or pet.pinInBackground(); you can save a parseObject in local storage , to query objects in local storage you need set query.fromPin(true)
https://parse.com/docs/android/guide#objects-the-local-datastore
"done" method fires when the background task ends.

Android SQLite Query, Insert, Update, Delete, Always Need to be On Background Thread?

I currently use Loaders to grab data from my ContentProvider (to enable auto-updating of my Cursors). This approach is straight-forward for Querying the database, though, it seems ill suited for any other DB operation (such as Insert, Update, Delete).
My questions are:
Do all SQLite operations need to be on a background thread, or is it safe to do simple operations like Inserting, Updating, or Deleting a single row on the UI thread?
What is a nice design patter to ensure all queries go through a background thread? I would like to implement AsyncTask, should I create a SuperTask so to speak that extends AsyncTask and Executes each SQLite operation? (Bonus: Can you provide bare-bones example?)
I have done SQLite operations on my UI Thread. I guess the question really becomes whether your queries will ever take a long time or not. I've never had my application crash from taking too long to execute SQL calls on my SQLite database.
With that said, if you plan on writing complex queries that can take time to load you would want to run it as an AsyncTask or Thread and use callbacks to update your UI if need be.
This is a great tutorial on SQLite on Android (It also addresses some of the complex sql timing issues you were talking about):
http://www.vogella.com/tutorials/AndroidSQLite/article.html
All SQLite operations do not need to be on a background, but should be. Even simple row updates can impact the UI thread and therefore application responsiveness.
Android includes the AsyncQueryHandler abstract class:
A helper class to help make handling asynchronous ContentResolver queries easier.
Here are two example implementations from Using AsyncQueryHandler to Access Content Providers Asynchronously in Android. A member class:
class MyQueryHandler extends AsyncQueryHandler {
public MyQueryHandler(ContentResolver cr) {
super(cr);
}
#Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// query() completed
}
#Override
protected void onInsertComplete(int token, Object cookie, Uri uri) {
// insert() completed
}
#Override
protected void onUpdateComplete(int token, Object cookie, int result) {
// update() completed
}
#Override
protected void onDeleteComplete(int token, Object cookie, int result) {
// delete() completed
}
}
An anonymous class:
AsyncQueryHandler queryHandler = new AsyncQueryHandler(getContentResolver()) {
#Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
if (cursor == null) {
// Some providers return null if an error occurs whereas others throw an exception
}
else if (cursor.getCount() < 1) {
// No matches found
}
else {
while (cursor.moveToNext()) {
// Use cursor
}
}
}
};
Further details:
Implementing AsyncQueryHandler
http://www.trustydroid.com/blog/2014/10/07/using-asyncqueryhandler-with-content-provider/

Android sqlite insert / multiple reads from many threads

I don't know how to handle this correctly without getting database locked errors.
My app basically downloads many items in batches of 100 rows (~ 60.000 items) and inserts them in the database. Each batch of 100 rows is processed into a transaction.
The main activity allows the user to navigate between screens (fragments) while records are being downloaded and inserted. Most of the other screens contains read data from the database. I get a lot of database lock errors during reading. All readings are done in the main activity (not fragments) in different async tasks
So far I just used the "classic approach"
public class DBAdapter {
public DBAdapter(Context ctx) {
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE_TABLES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Utils.log("Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
onCreate(db);
}
public DBAdapter open() throws SQLException {
database = DBHelper.getWritableDatabase();
return this;
}
public void close() {
DBHelper.close();
}
Then on my activity's onCreate() I call db = new DBAdapter(context); and each time I am doing an database operation (read/write) I call db.open() and after the insert/read is done I call db.close()
My questions are:
what would be the best approach to this situation ?
Considering I do a lot of write/read would it be better to call db.open on onCreate and db.close() on onDestroy() ? Would this be better than calling open/close each time I need to access the database ?
What do I need to do to avoid database locking on reading ?
I had a exactly similar situation like yours. In addition to what you described, in my app the user also can update the database through input on the screen.
The way I resolved it ( I don't know if it's the best way, but I hardly see any locking issue now)
Make a singleton class derived from SQLiteOpenHelper to make sure only one instance is running at any given time.
Implement ContentProvider class for insert/update/delete/query operations. Make all those functions 'synchronized'
Only close the db in ContentProvider's shutdown function. I do a very frequent db operations, so I don't want to open/close everytime. But I am not sure if it's the correct way of handling it.
Do access DB only through ContentProvider interface from anywhere
A very simple approach, or maybe a workaround is using synchronized methods for opening and closing the database object. I don't really know if it's the best practice, but at least it's simple and easy. Add this methods to your DBAdapter Class, and use them instead of db.open and db.close. The use_count attribute simple holds how many times open has been called. Initialize it with a value of 0. Also, in order to make it work on your solution be sure to pass the same DBAdapter object between the fragments. Don't create a new one everytime :
private int use_count = 0;
public synchronized void doOpen()
{
use_count++;
this.open();
}
public synchronized void doClose()
{
use_count--;
if (use_count == 0)
{
this.close();
}
}
Consider wrapping the SQLite database in a ContentProvider and using CursorLoader to do the queries from the various activities & fragments. This isolates the management of the database from the Activity/Fragment life cycle and can result in many fewer open/close cycles.
You may still run into contention between the reads and writes, but having all the database interaction in the same module should make it easier for you to address these issues.
Some interesting links: http://www.vogella.com/articles/AndroidSQLite/article.html#todo
When to use a Content Provider

Android, How to manage opening/closing database connection when we have multiple tables?

I am looking for best approach to handling database connection. I have designed my application base on following method and works fine. However, sometimes application crashes especially on old model devices. Please look at my following method.
I have a DatabaseHelper class which all of tables will be created here. This class is like this:
public class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
Log.i(TAG, "Object created.");
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CRT_TBL_1);
db.execSQL(CRT_TBL_2);
db.execSQL(CRT_TBL_3);
db.execSQL(CRT_TBL_4);
db.execSQL(CRT_TBL_5);
db.execSQL(CRT_TBL_6);
db.execSQL(CRT_TBL_7);
db.execSQL(CRT_TBL_8);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(DatabaseHelper.class.getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data.");
onCreate(db);
}
}
As you have seen, I have 8 tables which provides data for 8 different activities. Implementation of handler class for one activity is like following code.
public class DatabaseHandler_1 {
private final String TAG = "DatabaseHandler_1 ";
private DatabaseHelper dbHelper;
private SQLiteDatabase database;
public DatabaseHandler_1 (Context context) {
dbHelper = new DatabaseHelper(context);
Log.i(TAG, "Object created.");
}
public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}
public void close() {
dbHelper.close();
}
// ... Other methods insert, update, query, ...
}
Finally, based on required information one or some of them will be used in each activity.
public class Activity_1 {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "Try to create activity...");
// Creating Database/Table
dbHandler_1 = new DatabaseHandler_1 (this);
dbHandler_1 .open();
dbHandler_2 = new DatabaseHandler_2 (this);
dbHandler_2 .open();
dbHandler_3 = new DatabaseHandler_3 (this);
dbHandler_3 .open();
}
#Override
protected void onDestroy() {
super.onDestroy();
// Closing database
dbRecipesHandler.close();
dbFavoritsHandler.close();
dbShoppingHandler.close();
}
// Other methods for displaying data...
}
When crashes happens logcat shows the connection is close while my application tries to query in database. I think scenario is like this:
User opens 1'st activity then he goes to second activity and then he goes to third activity. Now, if user clicks on back button third activity will be closed and onDestroy() method of this activity closes database connection. Because, second activity is still in memory, activity assumes that the connection is still open and when it wants to query into database, crash happens.
Logcat shows a message like this: Database connection is close. You wanted to query...
One solution is instead of letting Android OS handles database connection, we manually open connection and use it the manually close it.
Second solution is in Handler class manually open and close connection for each method.
What is you suggestion? did you have any experience about it?
Any suggestion would be appreciated.
In general I would suggest you consider wrapping your data with Content Providers then using Loaders in your activities to mingle data with the UI. It might seem like a lot of work, but among the many benefits of content providers you will not have to manage database connections or cursors within your activities. (Note, your DatabaseHelper class would remain the same)
Having done data both your way as well as with content providers in the different apps I've made, I would say content providers are almost always the way to go. It's always ended up being more maintainable and extendable in my experience, plus you get a lot of baked in features that would be really expensive to build yourself.
That said, if you really prefer the more direct approach you're currently using, I would at the least not tie the opening and closing of your connections to the activity's life cycle. Only open those connections at the instant you actually need data, get that data, then immediately close any cursors along with the connection itself.
Finally I solved the problem. I thought that I should open database one time in activity. I tried to open database again in onResume() method of each activity and closing it in onPause() of each activity instead of closing in onDestroy() method.
So far problem solved. Hope to don't see it again. If i face it again then will update/remove answer.

AsyncTask that accesses Sqlite database causes crash

I have a ListView which I need to populate using a background thread. The list needs to update as each item is retrieved. Below is a very simplified example of how I implement this.
public class DownloadTask extends AsyncTask <MyUserObject, Integer, String>
{
#Override
protected MyUserObject doInBackground(MyUserObject... myUserObj)
{
MyUserObject muo = null;
int nCount = myUserObj.length;
if( nCount > 0 )
muo = myUserObj[0];
muo.DownloadStuff();
return muo.getUserName();
}
protected void onPostExecute(String userName)
{
adapter.names.add(userName);
adapter.notifyDataSetChanged();
}
}
public class MyAdapterClass extends BaseAdapter
{
private ArrayList<String>names;
public MyAdapterClass(Context context)
{
names = new ArrayList<String>();
}
public fillList()
{
for( int i=0; i<users.length; i++ )
{
DownloadTask task = new DownloadTask();
task.execute(users[i]);
}
}
In the above example, 'adapter' is an object of type MyAdapterClass, and its fillList() method is what launches the threads. Calling notifyDataSetChanged() in onPostExecute() is what updates my ListView as data arrives.
The problem is, that I am accessing my sqlite database in "DownloadStuff()' which is called in 'doInBackground', and having multiple threads accessing the DB causes it to crash. (If I comment out all DB activities in here, then it runs fine). Below is how I try to workaround this problem, however it still crashes. Any advice on how I can have my ListView update as data is retrieved from a background thread?
Semaphore semaphore = new Semaphore(1, true);
public synchronized void DownloadStuff()
{
semaphore.acquire(1);
// ... DB operations ... //
semaphore.release(1);
}
I think your approach is wrong from it's beginning. Why do you want to start separate AsyncTask for each item you have to add to your adapter. Use onProgressUpdate to notify the gui for newly added items in the adapter. In this case you want have concurrent access to your db.
I'm not sure (because I'm really tired) but I think your ot using you synchronysed correctly.
you create a different instance of MyUserObject each time you do a async task, this means you never actually call Downloadstuff on the same instance hence no conflict, but on the other hand your database is unique being called by multiple MyUserObject hence conflict.
what you want to do is have the same instance of muo in all your async task, this way they all call downloadstuff on the same instance and then synchronized will work preventing multiple access.
you also don't need the semaphoe here.
edit:
Mojo Risin answer is also very good, if you can save yourself the trouble by centralizing all you async tasks into one you should(less concurrent threads running around you have the better)

Categories

Resources