Example class to Export/Import a Realm database on Android (1/3)

One feature Glucosio users asked the most was complete database backup/restore. As you may already know, we’re using Realm to power our mobile database.

Realm is a replacement for SQLite & ORMs

One month ago, the Realm team released a very useful library for iOS projects called Realm Cocoa Converter (read their blog entry here). Cocoa Converer allows developers to export data in and out Realm in readable formats (like CSV). The library is written in Swift and it’s very easy to use:

// Example code to export database to CSV
let path = ... // Absolute path to the target Realm file
let destinationFolder = ... // Absolute path to the folder in which to save the CSV files

let exporter = CSVDataImporter(realmFilePath: path)
exporter.exportToFolderAtPath(outputFolderPath: destinationFolder)

But, hey, what about Android? I promptly pinged Realm on Twitter and here’s what I’ve got:

So Converter for Android will not probably happen overnight. What can we do meanwhile? Although you can manually write your own class to import/export data in CSV (we did it too), let’s find a simpler alternative to simply export and import a database instance on Android.

Realm (-java) comes with an useful method: realm.writeCopyTo(File file). It can simply export your database in a .realm file somewhere.

RealmBackupRestore.class

So, we start making two methods to backup and import data.

public void backup() {
try {
// create a backup file
File exportRealmFile;
exportRealmFile = new File(EXPORT_REALM_PATH, EXPORT_REALM_FILE_NAME);

// if backup file already exists, delete it
exportRealmFile.delete();

// copy current realm to backup file
realm.writeCopyTo(exportRealmFile);

} catch (IOException e) {
e.printStackTrace();
}
    realm.close();
}
public void restore() {
String restoreFilePath = EXPORT_REALM_PATH + "/" + EXPORT_REALM_FILE_NAME;

copyBundledRealmFile(restoreFilePath, IMPORT_REALM_FILE_NAME);
Log.d(TAG, "Data restore is done");
}
private String copyBundledRealmFile(String oldFilePath, String outFileName) {
try {
File file = new File(activity.getApplicationContext().getFilesDir(), outFileName);

FileOutputStream outputStream = new FileOutputStream(file);

FileInputStream inputStream = new FileInputStream(new File(oldFilePath));

byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, bytesRead);
}
outputStream.close();
return file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

As you can see, the restore method just replaces the local .realm file with the previously exported one.

Also remember to define the three constants EXPORT_REALM_PATH, EXPORT_REALM_FILE_NAME, IMPORT_REALM_FILE_NAME, with respectively the path where you want the file exported to, the name of the exported file (should be something.realm) and the name of your database (default is “default.realm”).

For example, you might want to export the database in the Downloads directory and name it “glucosio.realm” (well, I don’t think so):

private File EXPORT_REALM_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
private String EXPORT_REALM_FILE_NAME = "glucosio.realm";
private String IMPORT_REALM_FILE_NAME = "default.realm"; 
// Eventually replace this if you're using a custom db name

Ask for permissions

Anyway the code above will not work without Storage permissions. Go in your AndroidManifest.xml and add:

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

Then ask for permissions in your class:

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void checkStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

if(permission != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}

If we don’t have storage permissions, we will ask the user to grant them.

I put the final code on a Gist, so you can read it better.

I’ll write another post soon to integrate this class with Google Drive’s API and sync our database in the cloud with other devices.

Happy coding :)


Do you want to build useful things that could have a big impact on people’s lives? Join us at Glucosio.