Feeds:
Posts
Comments

Posts Tagged ‘database’

In some of my apps, I need to use a pre-existing database, which is very likely to be upgraded in a later release and which could be pretty big (over the roughly 1MB limit of an asset file). After some experiments and searching on the Web (especially on StackOverflow), I’ve settled with the following code. The basic idea is

1. if the database doesn’t exist yet when it is to be opened, combine the split files into a database file, and open it.

2. if the database version is changed, delete the database file in onUpgrade().

//The Android's default system path of your application database.
private static final String DB_PATH = "/data/data/com.mypackage.myapp/databases/";
private static final String DB_NAME = "mydb.db";
private static final int DB_VERSION = 2;
private static final String DB_SPLIT_NAME = "mydb.db.00";
private static final int DB_SPLIT_COUNT = 3;
private SQLiteDatabase m_database;
private final Context m_context;

/**
 * Constructor
 * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
 * @param context
 */
public MyDB(Context context) {
 super(context, DB_NAME, null, DB_VERSION);
 this.m_context = context;
}

public static MyDB openDatabaseReadOnly(Context context) {
 MyDB db = new MyDB(context);

 try {
   db.createDataBase();
 } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
 }

 db.openDataBase(SQLiteDatabase.OPEN_READONLY);
 return db;
}

public static MyDB openDatabaseReadWrite(Context context) {
 MyDB db = new MyDB(context);

 try {
   db.createDataBase();
 } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
 }

 db.openDataBase(SQLiteDatabase.OPEN_READWRITE);
 return db;
}

/**
 * Creates an empty database on the system and rewrites it with your own database.
 */
public void createDataBase() throws IOException {
  boolean dbExist = checkDataBase();
  if (dbExist) {
    /* By calling this method here onUpgrade() will be called on a
    ** writable database, but only if the version number has been bumped.
    */
    SQLiteDatabase db = this.getWritableDatabase();

    if (db != null) {
      db.close();
    }
 }

 dbExist = checkDataBase();

 if (!dbExist) {
   try {
     /* By calling this method an empty database will be created into the 
     * default system path of your application so we are gonna be able 
     * to overwrite that database with our database.
     */
     SQLiteDatabase db = this.getReadableDatabase();

     if (db != null) {
       db.close();
     }
     copyDataBase();
   }
   catch (IOException e) {
     Log.e("DB", e.getMessage());
      throw new Error("Error copying database");
    }
  }
}

/**
 * Check if the database already exist to avoid re-copying the file each time you open the application.
 * @return true if it exists, false if it doesn't
 */
private static boolean checkDataBase(){
   SQLiteDatabase checkDB = null;
   try {
     String path = DB_PATH + DB_NAME;
     checkDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
   }
   catch (SQLiteException e){
     //database does't exist yet.
   }

   if (checkDB != null) {
     checkDB.close();
   }

   return checkDB != null ? true : false;
}

/**
 * Copies your database from your local assets-folder to the just created empty database in the
 * system folder, from where it can be accessed and handled.
 * This is done by transferring byte stream.
 * */
private void copyDataBase() throws IOException {
  // Path to the just created empty db
  String outFileName = DB_PATH + DB_NAME;
  //Open the empty db as the output stream
  OutputStream output = new FileOutputStream(outFileName);
  //transfer bytes from the inputfile to the outputfile
  byte[] buffer = new byte[1024*8];

  AssetManager assetMgr = m_context.getAssets();

  for (int i = 1; i <= DB_SPLIT_COUNT; i++) {
     //Open your local split file as the input stream
     String fn = DB_SPLIT_NAME + String.valueOf(i);
     InputStream input = assetMgr.open(fn);
     //Log.i("DB", "opened " + fn);

     int length;
     while ((length = input.read(buffer)) > 0) {
       //Log.i("DB", "read " + String.valueOf(length));
       output.write(buffer, 0, length);
       //Log.i("DB", "write " + String.valueOf(length));
     }
     input.close();
   }

   //Close the streams
   output.flush();
   output.close();
}

private void openDataBase(int flags) throws SQLException{
  //Open the database
  String myPath = DB_PATH + DB_NAME;
  m_database = SQLiteDatabase.openDatabase(myPath, null, flags);
}

@Override
public synchronized void close() {
  if (m_database != null)
    m_database.close();
    super.close();
  }
}

@Override
public void onCreate(SQLiteDatabase db) {
  // do nothing
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  if (newVersion > oldVersion) {
     m_context.deleteDatabase(DB_NAME);
  }
}

Read Full Post »