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
{
}
}
Related
For SQLiteOpenHelper, if I add a new table inside onCreate do I have to do anything inside onUpgrade? I am adding a completely new table. I believe I have to change the version number but that onUpgrade should remain empty. Is that correct?
If you want existing installs of the app to add this new table, then yes, you must increase the version and provide a suitable onUpgrade() implementation, as well as adding the table in onCreate() (which you stated you have already done).
An empty onUpgrade() implementation is not sufficient; it has to actually do something. Some people drop all tables and just call onCreate() directly, but this obviously doesn't work well if you are trying to keep existing data. I usually use the fall-through switch idiom, so that if a user is more than one version behind (e.g. you publish a version 3 and a user is still on version 1) they will go through all the necessary upgrades sequentially:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL("CREATE TABLE " + ...);
// no break statement, so case 2 will execute after this.
case 2:
// more execSQL(), etc
}
}
onCreate() will not be called if a user already has installed your app previously. So you need to create the new table in onUpgrade(), too. Be sure to increase the version number of your database.
I suggest putting the code to create the table in a helper method so that you can call it from both callback methods. This will reduce the chance of an error in case you need to change the code to create the table.
onUpgrade will only be called if you increase the version number.
To implement it you must recreate the tables with any changes you have made and copy over any existing data. There are many tutorials on this topic.
It is not necessary to implement if you are still learning, but if you don't and you make any changes to your schema you'll need to uninstall the app from the device or the changes won't be applied.
This is a trivial question, but I am afraid to put in production wrong code and that testing in devices/emulator could lead to cache problems that do not mirror the reality.
My assumptions:
As well documented on SO, I need to add a column to my DB, I decided to use ALTER table ADD column
in onUpgrade(), and to change the version in the constructor of the DB from 1 to 2, so that the constructor will recognize that is running the new version and the onUpgrade() function should be triggered.
My 2 problems:
1) MOST IMPORTANT. Let's assume old users will upgrade successfully the db, but what happens with new users that still have to create even the first row of the DB, will they be directed to OnCreate() and not onUpgrade() because version is 2, or to on OnCreate() and then onUpgrade(), or almost impossible directly in OnUpgrade() skipping for some API reason even onCreate()?
In other terms do I need to update the new column changing the old onCreate() comprehending the new added column?
2) in onUpgrade() after
ALTER <table> ADD <column>
logically do I have to CREATE a new table right? Should I call onCreate() that as an updated Table( ex. instead of the original 4 column, now has 5 columns)?
When getWritableDatabase() is called, it checks the database file. If it does not exist, onCreate is called. If it does exist, but has a wrong version, onUpgrade is called.
So onCreate is responsible for creating the database schema of the current version, while onUpgrade is responsible for changing some existing database to have the schema of the current version.
You could share code between onCreate and onUpgrade, but calling that code is your own responsibility; the framework will not check the version again after the onXxx callback has returned.
I want to know if it is possible to add a table to my remote database after the app has been running on my device for a couple of weeks, and still work?
For instance, if I'm using a Android device and have a simple game with 3 levels using SQLite db. Now I want to add a 4th level to the game, without losing progress on the other 3 levels or having to re install the app to accommodate for db changes?
In simple words YES it's possible. You can change your database design with out losing any data. You can achieve by overriding the 'onUpgrade' method in your database class which extends SQLiteOpenHelper.
You need to change the database version number when you update your app. If the database version number is greater than the previous one then onUpgrade method get called.
#Override
public void onUpgrade(SQLiteDatabase db, int newVersionNumber, int oldVersionNumber) {
// Do your Changes here. You can Alter table, Drop column etc
}
Remote Database - Its not linked with app. So you can change what ever you want. It won't affect your app. But you need to handle it efficiently.
Hope it helps.
Yes. it is possible, you can upgrade it.
You must set old and new database version.
public void onUpgrade(SQLiteDatabase db, int newVersionNumber, int
oldVersionNumber)
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.
I need to recognize first launch of my application or activity.
At this time I need to get some information from server create local database and save info to it. What is the best way to do this?
Create any preferences for example FirstLaunch and set true \ false to it.
Check whether my database exists or not.
Something else?
PS. All server calls must be into one transaction. Ormlite supports transactions?
Thanks.
For the "create database at first run"-purpose, you should use an SQLiteOpenHelper, which offers you the onCreate()-method that is called when:
[...] the database is created for the first time.
The Database-file itself will be created for you (you don't have to do this manually). In this method, you can then perform actions like populating your database with standard entry's.
If you want to populate the database with informations you get from your server, there might be a problem when there is no Internet-connection available.
In this case, I would check if there is a connection available:
If there is, get your informations.
If not, show a Toast or some other notification to inform the user.
To determine if your Database has be populated with the standard entry's, you can use the database-version which is also provided by the SQLiteDatabase-class:
When you first create your Database-object, you call
SQLiteOpenHelpers constructor and pass it 0 as the Database
version.
If you successfully populated your database, you use
setVersion()-method to alter it to 1.
Later in the onOpen()-method, which is called when the
database is opened, you can check if the database was populated by
using the getVersion()-method.
If it is populated, call the super-method to open it.
If not, try populating it.
Further more, the getReadableDatabase() / getWritableDatabase()-methods should be called off the main-thread anyways because:
Database upgrade may take a long time, you should not call this method
from the application main thread, including from
ContentProvider.onCreate().
So getting the informations from the Internet can take place in the onCreate() and in the onOpen()-method (if it wasn't successful at the first try). You can (for example) use a Service to do this.
If you want to solve this problem with database:
Create database with MyDatabasaVersion table and store your version in a single row, for example db_version default value is 0. First time when the application starts you check the db_version if 0 you need to start the syncronisation, after it is finishing set the db_version to 1.
The easiest way should be sharedpreferences. you can call it everywhere form the application context and you can put boolean values in it.
Here are all Android storages.
you should try first option Create any preferences for example FirstLaunch and set true \ false to it.