Si vous utilisez une base de données interne pour votre application Android, vous utilisez sûrement un ContentProvider. C’est une solution plutôt élégante et très pratique. En revanche, avez-vous déjà essayé de restaurer une base de données SQLite précédemment sauvegardée ?

Android database

Introduction

J’ai mis en place un plugin de sauvegarde et restauration pour One Launcher. Ce plugin se contente simplement pour :

  • la sauvegarde : de copier les bases de données internes sur l’espace de stockage externe (la carte SD par exemple)
  • la restauration : de copier les sauvegardes présentent sur l’espace de stockage externe vers le répertoire privé de l’application pour ses bases de données

Après quelques réglages, la sauvegarde fonctionne très bien. En revanche, j’ai rencontré une autre difficulté avec la restauration. En effet, même si la restauration ne retournait aucune erreur, elle ne semblait pas être prise en compte.
Le ContentProvider étant démarré en même temps que l’application, il semble que le fichier ne soit lu qu’au démarrage. Ensuite, il est seulement écrasé régulièrement par le ContentProvider. Voilà pourquoi la restauration n’est pas prise en compte.

Solutions

Mise à jour de la base de données

Le premier réflexe est de contourner le problème en mettant en place un service de synchronisation qui va se charger de mettre à jour la base de données interne à partir de données de la base de données sauvergardée.
Pour être honnête, je n’avais pas le courage de développer ce service. De plus, ce système n’est vraiment pas optimisé puisqu’il va nécessiter de parcourir toutes les données sauvergardées pour ensuite les insérer dans la base de l’application. Ce traitement va consommer de la mémoire et surtout des ressources CPU.

Rechargement du ContentProvider

Gardons la solution qui consiste à écraser le fichier de la base de données interne par le fichier de sauvegarde présent sur la mémoire externe. Il faut simplement trouver un système qui permet de demander au ContentProvider de recharger le fichier. Or depuis la version 5 de l’API Android, il existe une petite méthode qui autorise ce genre de manipulation.

Voici donc le code à mettre en place et à appeler après avoir écrasé le fichier de votre base de données interne de votre application :

ContentResolver resolver = context.getContentResolver();
String authorityName = "mycontentprovider";// nom de l'autorité de votre content provider
ContentProviderClient client = resolver.acquireContentProviderClient(authorityName);
MyContentProvider provider = (MyContentProvider)client.getLocalContentProvider();
provider.resetDatabase(this);
client.release();

Il faut également implémenter la méthode resetDatabase() dans votre ContentProvider (MyContentProvider dans cet exemple) :

// helper utilisé par le content provider
protected SQLiteOpenHelper dbHelper;

public void resetDatabase(Context context) {
    if (dbHelper!=null) {
        dbHelper.close();
        dbHelper = new DbHelper(context);
    }
}

Et voilà ! Après chaque restauration, le fichier interne sera fermé puis rechargé afin d’être pris en compte par le content provider.

Conclusion

En cherchant un peu, nous avons obtenu ici une solution simple, efficace et performante.

Cet exemple met en évidence que parfois la solution la plus simple est la meilleure. Oui, oui. Cela semble évident dit ainsi. Pourtant ce n’est malheureusement pas toujours le cas… 🙁