Application releasing in Update/Upgrade mode with SQLite databse file update - android

I have developed an android app that accesses local sqlite database inside the app.
I have a question of how to upgrade the app. In this case, say if an application source code changes OR the database data/structure changes, how do I package these changes?
do i have to repackage complete app and make it available as a new app version ? or can I just package only the changed files into a much smaller build size and push it to market ?
In general, how is the application upgrade/update process carried out ?

If you're extending SQLiteOpenHelper (you should be), its constructor takes a version parameter, which is an integer value you should define in a constant like DATABASE_VERSION somewhere.
Override the onUpgrade method and implement the logic for upgrading your schema and/or data.
When you increment the DATABASE_VERSION constant (in an app update for instance), any existing installs that have a lower version will fire the code in onUpgrade.

Change DATABASE_VERSION of your db and next time you will start the app
the db will be recreated.

For both, you basically just export a new version of your application from Eclipse, and upload the new APK through your market account.
Application version changes are handled by a tag in the manifest: android:versionCode. Each time you export a updated APK, you need to increment the version code. versionName is just the label that's displayed to users in the market, so can be whatever you like.
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.package"
android:installLocation="auto"
android:versionCode="17"
android:versionName="0.74">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="12" />
<uses-permission
android:name="android.permission.INTERNET"></uses-permission>
...
As for the database, the easiest way to do it is to sub-class SQLiteOpenHelper. Then, in your sub-class you can have something like this:
private class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "mydatabase.db";
private static final int DATABASE_VERSION = 45;
public DBHelper(Context context)
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
...
The SQLiteOpenHelper handles opening the database, and updates when the application launches. In the above example, the database version is 45. If you increment that, and upload a new APK to the market, an onUpgrade() method is called, which allows you to update users old databases to your new version.

Related

Unable to load Database from Asset Folder (Android Studio)

quick background - I have no real programming knowledge so think complete beginner!
I used the below guide to load a database from the assets folder and it worked fine
http://www.javahelps.com/2015/04/import-and-use-external-database-in.html.
I now want to adjust this slightly so it loads a different SQLite database which I have created using DB Browser for SQLite but it is throwing the following error:
Missing databases/Exercisesthree.db file (or .zip, .gz archive) in assets, or target folder not writable
I have placed the new database (Excercisesthree.db.zip) in the same assets folder as the database that works (I have also left the unzipped file there too (Excercisesthree.db).
I altered the DatabaseOpenHelper class to open the Excercisesthree.db instead of the other db (code below) but for some reason it doesnt work. I suspect its something to do with the format of the database as I've hardly changed the code
package com.example.mat.externaldatabasedemo;
/**
* Created by Mat on 24-Jan-17.
*/
// http://www.javahelps.com/2015/04/import-and-use-external-database-in.html
import android.content.Context;
import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;
public class DatabaseOpenHelper extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "Exercisesthree.db";
private static final int DATABASE_VERSION = 1;
public DatabaseOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
Here's a link to the database file:
https://1drv.ms/u/s!AupGvbDoJdp9i26l9oO5CcCGf2I0
This is the location of the database files:
C:\Users\Mat\AndroidStudioProjects\ExternalDatabaseDemo\app\src\main\assets\databases
Ok I've sorted it and confirm it was nothing to do with the Database format. In the end I created a new project and followed the original guide but changed it to the new database.
I think what must of happened is I'd changed some part of the code somewhere along the way and it stopped working. When testing it however it appeared to be working because the original databse had already been loaded onto the emulator and so it masked the fact that the database was no longer loading from the assets folder.
I would have like to have found out exactly what part of the code was missing and stopping it to work to understand a little more and report back but dont think I'll have time

SQLiteAssetHelper NullPointerException at getReadableDatabase()

Because #CommonsWare suggested (in the comments to this answer) using the Android SQLiteAssetHelper library, I decided not to use Using your own SQLite database in Android applications method (a popular SO answer) to copy my pre-populated database from my assets folder to the app database folder.
Following the Android SQLiteAssetHelper directions, I set up my project like this:
Since I am using gradle, my database was in src/main/assets/databases/test.db.zip.
I used the .zip extension because the directions said
Earlier versions of this library required the database asset to be
compressed within a ZIP archive. This is no longer a requirement, but
is still supported. Applications still targeting Gingerbread (API 10)
or lower should continue to provide a compressed archive to ensure
large database files are not corrupted during the packaging process.
and I want to support earlier versions of android.
My database class is similar to the following:
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "test.db.zip";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
Again, I used the .zip extension for the DATABASE_NAME value because the directions said
...you must provide...a SQLite database inside the databases folder
whose file name matches the database name you provide in code
(including the file extension, if any)
However, when I do SQLiteDatabase db = getReadableDatabase(); I get a NullPointerException. What is the problem?
These SO questions and answers are not the same issue:
NullPointerException with Android SQLiteAssetHelper
SQLiteAssetHelper:Couldn't open database for writing (will try read-only)
SQLiteAssetHelper NullPointerException only on some devices
I set up the question to make the answer somewhat obvious, but here it is:
Contrary to what the Android SQLiteAssetHelper directions make it sound like (at the time of this writing, anyway. hopefully they will clarity them in the future), the DATABASE_NAME value should not include the .zip extension. Change your code to
private static final String DATABASE_NAME = "test.db"; // no .zip extension
but keep src/main/assets/databases/test.db.zip as it is, and everything should work.

Android concerns with restore database

Imagine the following scenario (I allow backup / restore from my app, I'm doing backup / restore white the entire file.db):
The user make backup of the database.
In the future I do an update on my application which has a new version of the database.
what would happen if the user restore the database with the old version?
How can I avoid this kind of problem?
It would be a good idea to use BackupHelper? I did a simulation of the worst scenario of my database and gave 20k, BackupHelper is recommended for less than 1mb, it would be a good idea to use it? I think my app will never exceed 100kb.
You access SQLite databases via a SQLiteOpenHelper, which provides three callbacks: onCreate(), onUpgrade() and onOpen().
The constructor declares a version parameter, and internally it compares the database version (which is stored in the file) with the supplied argument. If the requested version is newer than the file's, your onUpgrade(db, old, new) is called and you get a chance to alter tables, fill rows and so on.
The restore procedure should simply close all open cursors and helpers and copy the new file in.
May be this is not the best approach but you can do it as:
1- Store the DB Version in the database.
2- After restoring the database, check the DB Version and do the required changes accordingly. Like
void afterRestoration()
{
long dbVersion = get from db;
if(dbVersion == 1)
{
alter table1 add column1;
}
else
{
}
}

Android dealing with database versions regarding updates

Is there any documentation on how to best deal with database upgrades in android?
I am developing an application and have been testing it on my own telephone. All works fine, over the past few deploys I had to add some columns to my table and due to upgrade statements that are executed if the old database version is lesser then a certain database version.
However when I try to run the application on another phone, that gives errors due to the fact that there is no previous version and thus the column isn't added.
Is there any best practice or documentation on how to handle database upgrading and versioning? I tried googling around for specific questions, but much good didn't come out of that.
Here's the relevant code I am using at the moment:
private static final int DATABASE_VERSION = 11;
private static class LocalLoginDatabaseHelper extends SQLiteOpenHelper {
LocalLoginDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d(TAG,DATABASE_CREATE);
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(oldVersion < 11) {
Log.d(TAG + "Upgrade",DATABASE_ALTER);
db.execSQL(DATABASE_ALTER);
}
}
}
Thanks
Is there any documentation on how to best deal with database upgrades in android?
Use SQLiteOpenHelper, which will give you control when a schema change is detected, so you can upgrade the database.
UPDATE
However when I try to run the application on another phone, that gives errors due to the fact that there is no previous version and thus the column isn't added.
Your DATABASE_CREATE needs to have the column as well. For a new install (or after the user does Clear Data on your app), there is no existing database, and so onCreate(), not onUpgrade(), is called.
Shameless Plug: I know you have this issue resolved but I am working on an open source set of DSL's that makes it easy to create SqliteOpenHelper/ContentProvider/Contract API and manages upgrades through migrations http://robotoworks.com/mechanoid-plugin/mechanoid-db
Its still very early days and I am busy writing docs however its already useful to anyone working with sqlite in Android and the more people using it will make it better :)

Android Architecture: Using multiple ContentProviders and onUpgrade event

My application has two database tables: Products and ShoppingCard. So I created a ProductContentProvider and ShoppingCardContentProvider. Each ContentProvider invokes in its onCreate() method a private class that is child of SQLiteOpenHelper.
From my point of view I would make a global static variable DATABASE_VERSION in a separated ConfigBean that is responsible for both content providers. So if I update that all tables are updated.
=> That does not work. Simply the onUpdate event is never fired.
If you specify a DATABASE_VERSION in each content provider, but with different version numbers in each content provider
=> That does not work. Also it makes no sense, from my point of view, because the paramater in SQLiteOpenHelper is called DATABASE_VERSION not TABLE_VERSION. So in other words, you cannot update any table without updating/throwing an event on all onUpgrade listeners.
If you specify a DATABASE_VERSION in each content provider, but with equal version numbers in each content provider.
=> That works.
Question:
Why can't you make the DATABASE_VERSION a public static variable outside to handle upgrades globaly, or am I completely on the wrong path with my architecture?
The solution to my problem was to create a base class to both content providers. This class holds the only instance of SQLiteOpenHelper. This also ensures that all database tables are created.
I found this information in the post of Ali Serghini, November 5th, 2010.
Okay I have found the reason for the strange behaviour:
I think my approach to make the DATABASE_VERSION an external parameter is right, if you have multiple ContentProviders.
I did just forget that there is yet another ContentProvider: A simple ConfigTable to store the settings. I think I hade a mix of different DATABASE_VERSION values in the end, that leads to re-creating the database on every startup.
After referencing a single param from all ContentProviders, everything worked as expected.
Thanks anyway,
Sebastian

Categories

Resources