Donnerstag, 3. April 2014

BARACUS from Scratch - Part 7 - Android SQLite HotBackup and HotRecovery

Table of Contents

In this tutorial I am going to show You, how to hot-backup the SQLite Database of Your Application. 
If You rely on Baracus' migr8, even old Databases can be restored automatically and updated to the latest level. This offers You a flexible mechanism to deal backup and upgrade issues.

Previous Tutorial : Automatic Form Validation

You can download the sourcecode from here

Note : I found a pitfall; to log the last start/end date I added an onDestroy() listener to the configuration service in order to update the regarding table. This runs into an error, if the database is shutdown for restoring, so I simply caught the exception. Baracus has no mechanism atm which allows You to ask for the lifecycle state of the container. This issue will be solved soon. Current development version is 0.8-SNAPSHOT, so expect this issue to be solved somehow in 0.8+.

Baracus relies on the effect, that Android keeps an open file handle to the database. This behaviour
could be verified on all Samsung Devices I own (S3 mini, S4, Google Nexus 10), so if anybody faces a
misbehaviour on a certain device, any email notification about this issue would be pretty welcome

Before all : Prerequisites 


In order to perform android database backups You must add the WRITE_EXTERNAL_STORAGE privilege to the android manifest

<manifest>
...
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

Once You have added this privileges, Your app is allowed to write to the device's external storage (phone : internal phone storage).

Here we go!

Step 1 : Define a button in order to fire the backup procedure

Yes, a button. Simple and easy to implement, huh? We need it to start the backup ;-)

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Perform Backup"
android:id="@+id/btnPerformBackup" android:layout_alignRight="@+id/buttonBackup" android:layout_alignParentTop="true"
android:layout_marginTop="39dp"
android:onClick="onButtonBackupClicked"/>

Now we have to wire that button

Step 2 : Call the built-in Backup function

Next step is to define the callback function in the HelloAndroidActivity :

public class HelloAndroidActivity extends Activity {
...
static String backupName;
...
public void onButtonBackupClicked(View view) {
        DBBackup.BackupResult result = DBBackup.performDatabaseBackup();
        if (result.isSuccessful()) {
            showPopup(this, "Successfully backed up "+result.getSize()+" to file "+result.getBackupDbName());
     backupName = result.getBackupDbName();
        } else {
            showPopup(this, "Backup failed :( Reason :"+result.getReason());
        }
    }

That's it. Database has been backup. I have no clue yet, if the backup file itself is portable to some other device type, but at the moment
 I doubt it, relying on the misportability of native structured storage between two platforms. If I get some other device type I'll give  a try. The name of the backup file is held in the static variable backupName. At the moment Baracus defines it own name built from timestamp, databasename and a .tac ending (truely assorted content).

A Backup is completely useless if You cannot perform any recovery with it, so here we go...

Step 3 : Implement ... another button

This button adds a new Customer to the table named Jane Doe. We need it, to show the impatient nonbelievers, that the current database truely has been modified.

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Modify Data"
        android:id="@+id/btnPerformDataModification" android:layout_alignRight="@+id/buttonModifiy" android:layout_alignParentTop="true"
        android:layout_marginTop="39dp"
        android:onClick="onButtonModifyClicked"/>

and here comes the callback :

public class HelloAndroidActivity extends Activity {
...
public void onButtonModifyClicked(View view) {
        Customer janeDoe = new Customer();
        janeDoe.setFirstName("Jane");
        janeDoe.setLastName("Doe");
        customerDao.save(janeDoe);
        showPopup(this, "Added Jane Doe");
    }

So when this callback is fired, a customer entity is created and written into the database. Basically this has got nothing to do with database backup, but it is better to see the the database modification within the customer subdialog.

Step 4 : Implement the recovery button

OK, now let's implement the recovery button. The impatient already checked if the data really has been modified by the button, right?

<Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Backup Database"
                android:id="@+id/btnRestorDatabase" android:layout_alignRight="@+id/buttonRestore" android:layout_alignParentTop="true"
                android:layout_marginTop="39dp"
                android:onClick="onBtnRestoreClicked"/>

Step 5 : Recovery

Recovery is a little bit more complicated because it requires the application context to shut down.
So if You did not break any rules like static dangling of objects and so on You should be able to shutdown, restore and relaunch the application without noticing it - if you are messing around with persistence calls in the destroy() lifecycle like me, You have to clean up Your backyard first. The restore util takes care of the shutdown, restore and relaunch process.

This looks like this :

 public void onBtnRestoreClicked(View view) {
        DBBackup.BackupResult result = DBBackup.restore(backupName);
        if (result.isSuccessful()) {
            showPopup(this, "Restore completed successfully.");
        } else {
            showPopup(this, "Restore failed due to reason :" + result.getReason());
        }
    }


Normally, You now can verify, that Jane Doe is not in Our database any more. Simply verify it by checking the table.

Conclusion

As You can see, Hotbackupping Your database is not complicated at all. At the moment I am quite confident that backups can be performed on each android device, but with the emerging device fragmentation problem this is not absulutely clear.

Upcoming tutorial : Managing the database with migr8

Keine Kommentare:

Kommentar veröffentlichen