I have an app with a backup and restore feature. Clicking a button to backup will copy the db file to external storage. Clicking the restore button will take the file from the external storage (if it exists) and copy it into the app, overwriting the existing db with the backup db file.
I have encountered the issue when an update is performed on a table. After a table is updated with data, the database with updated data will not copy into the external storage, or if I try to restore after an update is made, the file is not copied.
When an item is saved, the db is opened, then the following function is called to perform the update, then the db is closed.
public void saveItem(int ItemID, int ItemNumber, String itemnote)
{
ContentValues args = new ContentValues();
args.put("ItemNote", itemnote);
mDb.update("Items", args, "ItemID =" + Item+" and ItemNumber ="+ItemNumber, null);
}
After the update occurs, what is preventing the db file from being copied?
I am using the following code to import the db backup into the app. Again, this all works prior to the update statement being executed. Thanks in advance.
importdb.setOnClickListener(new View.OnClickListener(){
public void onClick(View arg0) {
final File DATA_DIRECTORY_DATABASE = getDatabasePath("MyDB");
final File DATABASE_DIRECTORY = new File(Environment.getExternalStorageDirectory(),"/MyApp");
final File IMPORT_FILE = new File(DATABASE_DIRECTORY,"MyDB");
File exportFile = DATA_DIRECTORY_DATABASE;
File importFile = IMPORT_FILE;
try {
exportFile.createNewFile();
copyFile(importFile, exportFile);
Log.i("Import", "Succesfull");
} catch (IOException e) {
e.printStackTrace();
}
}
});
private static void copyFile(File src, File dst) throws IOException {
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
After doing much testing on different devices and reviewing log files. It was discovered that on some devices the database is in write ahead logging mode (wal). This is not all devices, but on one of my test devices HTC Droid Incredible, wal is enabled, where as on the kindle fire wal is not enabled.
On the devices where wal is not enabled, there is no issue. On the devices with wal, the import and export of data was not working because the actual db file wasn’t current, as any changes reside in the wal file and do not get committed to the db file until a checkpoint for wal is hit.
To make sure the import and export functions are working properly, I need the db to contain the most up to date information. To accomplish this, a sqlite statement needs to be run to execute a wal checkpoint which will commit all information to the db file.
Before the export or import functions are run, the following sqlite command is executed to initiate a checkpoint and clear out the wal and commit the changes to the database.
PRAGMA wal_checkpoint
After the checkpoint is called the functions are working properly