Safe way to update database in ormlite android - android

My app used ormlite to communicate with Sqlite database. There are many screens that get data from ormlite. The problem is I want to update the database in background without user' knowledge (it's transparent to user) and my app use some CursorAdapters and Loaders to get data. The behavior look like this: my app check if there is new version in server, it will download new db file from server, then change current db file from local by new server db file in ormlite helper. While update progress is happening, user can change screen or view data from db normally (I just use the select query)
I have searched some answer, they advised use onUpgrade method, but how can I apply this in my case, because I want to change completely the database file? And how can I switch the database while selecting data?
Here is my db helper:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public DatabaseHelper(Context context){
super(context, "document.sqlite", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Category.class);
TableUtils.createTable(connectionSource, Book.class);
} catch (Exception ex) {
Ln.e(ex);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion,
int newVersion) {
try{
TableUtils.dropTable(connectionSource, Category.class, true);
TableUtils.dropTable(connectionSource, Book.class, true);
// get new one
onCreate(db, connectionSource);
}catch(Exception ex){
Ln.e(ex);
}
}
Any help would be appreciated!

I had similar situation in my project in which I had to refresh database with new data after checking for new data.After trying so many methods Finally I reached at one solution.I do not know if that solution is optimal one but after testing it is working fine.
Solution is as follows:-
I am getting new data in json form so I am creating a new blank database with temp_original-database-name.db and then populating it with new data(in your case you have complete database downloading from server , so you do not need extra helper for creating temporary database). After this data is populated then I am renaming this database temp_original-database-name.db to original-database-name.db using file system methods.
I have done testing and original helper instance used for original database still exists even after still second rename of database operation.and everything works fine.
Hope this can help.Please tell me if this helps and if you have any other question regarding this.

Related

How to recreate a database on an Android Application Update?

I'm new to writing Xamarin Android by about 8 months.
I have an application up on the Google Play Store and when the application first installs, it creates the sqlite database from code.
I had to make a database table change, I added a few columns.
When the application does it's auto update, where/how do I tell it to drop the database and recreate it, or is it automatic? I'd expect not.
I'm not worried about the data, it will be re-downloaded.
I looked at Assets, creating a text file and reading a command from it, but I can't remove the asset, so that was a dead end.
Thanks for any help.
I like to use the built-in SQLiteOpenHelper class to maintain the Sqlite version numbers and providing the process for upgrading the database.
Using the builtin Android.Database.Sqlite.SQLiteOpenHelper you can easily use it to maintain your database version and if the version changes, delete the database and start fresh with a blank one (no tables/no data).
Remember: This is destructive "upgrade"...
public class SqliteOnVersionChangeCreateBlankDB : SQLiteOpenHelper
{
new const string DatabaseName = "myDBName";
const int DatabaseVersion = 1;
public SqliteOnVersionChangeCreateBlankDB(Context context) : base(context, DatabaseName, null, DatabaseVersion)
{
}
public override SQLiteDatabase ReadableDatabase
{
get
{
try
{
return base.ReadableDatabase;
}
catch
{
File.Delete(DatabaseName);
return base.WritableDatabase;
}
}
}
public override void OnCreate(SQLiteDatabase db)
{
Console.WriteLine($"{db}");
// You can create the DB tables/data here if needed...
// or use your favorite SQLite framework/library later...
}
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Console.WriteLine($"{db}:{oldVersion}:{newVersion}");
if (oldVersion < newVersion)
{
// Normally this is where you would alter the existing schema to the new version
// but this is a destructive upgrade.
db.Close();
File.Delete(db.Path);
}
}
}
Usage:
Starting with a version of 1 in the SQLiteOpenHelper subclass:
const int DatabaseVersion = 1;
Execute this code:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
You now have a blank database that is assigned version 1. It is empty, no tables/data so use your favorite Sqlite ORM/framework/library to create the tables and populate it with data...
Unless the database version changes, executing this code each time your app starts will not delete the existing database:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
Later on, App is updated and you also need to change the database, so assign a new version number that is higher the last, 2 in this case, to the database.
const int DatabaseVersion = 2;
Execute the same code as before:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
You now have a blank database again, but it is assigned version 2. Again your favorite Sqlite ORM/framework/library to create the tables and populate it with data...
First you might want to confirm your intended behavior. I would track your .sqlite file to see what happens to it given your workflow.
For the most part when an application is being updated from Google Play Store, all of your application's data will stay put. (As it is only updating and not uninstalling -> installing again)
You can mimic this behavior by applying the following in your debug environment:
If you find yourself in a scenario where you need to update the database to associate it with a new application update, then you would need some mechanism to compare your database version and if it is older than the application's code expects, you would then apply a schema change and potentially seed the database with initial information.

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

SQLite updation upon android app's update

I have an app released on the android market which uses sqlite and displays data. I want to know if I am sending an update for the app by adding features, should I upload a new database? What happens when users already having my app, click on update? Will the database update on its own? If the users are downloading my app for the first time, they will certainly get the new db content...but what about the existing users?? I want to know if I have to explicitly update the database in the program
When you create your new version... If you change the version of the database... The onUpgrade function will run on all the existing users:
public static final int dbVersion = 2;
protected static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, dbName, null, dbVersion);
}
#Override
public void onCreate(SQLiteDatabase db) {
//create tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//what do you want to do to existing users? maybe recreate?
}
}
Why not create the sqlite database through code? That way your updates can update the SQL on the database (alter columns, add rows) without affecting the users existing data.
If you are changing database's attributes then on updation it will create problem and if the database's attributes are same then it will not have any effect...
You may use android.database.sqlite.SQLiteOpenHelper class it supports versions and migration mechanism

Android & Ormlite: Inserting data in DatabaseHelper onCreate

I am using Ormlite for the first time and I am trying to setup my DatabaseHelper to insert rows after creating the database's tables. I am getting a getWritableDatabase called recursively error when I do.
Here is my onCreate:
public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
try {
TableUtils.createTable(databaseType, connectionSource, User.class);
// Add test user
User test = new User("test", "12345");
getUserDao().create(test);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Unable to create databases", e);
}
}
The problem here was that #karnage was using an older version of ORMLite that had a bug with using the DAOs in the onCreate -- the pattern that he is using. This was fixed in version 4.6 (10/2010) and downloading and running the latest version works for him.
Here is the bug report:
https://sourceforge.net/tracker/?func=detail&aid=3117883&group_id=297653&atid=1255989
Here's the change log file to track new features and versions of ORMLite:
http://ormlite.com/changelog.txt

Problem in creating a database in SQLite in Android

Hi I am new to android and I have a problem in creating a database.
public class database extends ListActivity {
/** Called when the activity is first created. */
private final String MY_DATABASE_NAME = "myCoolUserDB.db";
private final String MY_DATABASE_TABLE = "t_Users";
Context c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> results = new ArrayList<String>();
setContentView(R.layout.main);
SQLiteDatabase mydb=null;
try
{
mydb.openOrCreateDatabase(MY_DATABASE_NAME, null);
} catch(Exception e){}
}
}
When I run this code it throws a run time exception. Please help me.
If you are going to call a static method like openOrCreateDatabase, do it on the class (SQLiteDatabase.openOrCreateDatabase(...)), not an instance. It's a lot clearer - the way you've done it looks like you're calling an instance method, so looks like a sure NullPointerException, which of course is misleading.
As someone else has stated, the stack trace would be the most useful thing when asking for help with an exception.
(Almost) never catch an exception without at the very least logging it. Don't just do nothing with it. There are of course exceptions to every rule, but let's not go there for the moment. Anyway, if you don't at least log it, you're just throwing away information that would tell you what went wrong when everything goes to crap later.
You shouldn't be using that method directly, and should instead be extending SQLiteOpenHelper . See the android developers page on data storage to get started (I'd post a link but apparently I'm only allowed one link in my post ?!), and since you've probably had to download the SDK to get going, look in the samples that come with it for the Notepad sample application. That contains a NotePadProvider class, which is a good example of both a content provider and database access, which often go hand-in-hand on android. I'd suggest compiling that application and making some simple changes to it before you jump into making your own one.
For working with sqlite database you need to create class extended from SQLiteOpenHelper:
private class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(UPGRADE_TABLES);
}
}
Then you can get access to db using DbHelper object:
DBHelper dbHelper = new DBHelper(Activity.this);
SQLiteDatabase db = dbHelper.getReadableDatabase();
I run into the same problem. It figures out that two bugs happens during development
dir "databases" was not existent
accendently ".db" was created as directory.
They following code cover both
File dbFile = getDatabasePath ("abc.db");
if (dbFile.isDirectory ()) {
dbFile.delete();
}
if (! dbFile.exists()) {
String path = dbFile.getParent ();
new File (path).mkdirs ();
}
database = SQLiteDatabase.openDatabase (dbFile.getAbsolutePath (), this, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY);
Hope this helps
I think SQLiteOpenHelper is only useful for "single table" databases. For multiple table applications I consider directly using SQLiteDatabase fit better to a good architecture.
This is a simple post which tells you how to insert data in to a SQLite database in Android and further more this links shows you how to retrieve data from a SQLite database in Android .

Categories

Resources