Accueil Nos publications Blog Le stockage sous Android : comment bien organiser ses données ?

Le stockage sous Android : comment bien organiser ses données ?

install-android-apps-on-sd-cardFaisons un petit test pour commencer.

Si je vous dis “stockage de données sur serveur”, quel est le premier mot qui vous vient à l’esprit ?
“Base de données !”

Si je vous dis “stockage de données sur mobile”, vous pensez à quoi ?
“Base de données !”
“Ah, et un peu de fichier aussi.”
“(Non, beaucoup de fichiers si on compte les images en fait…)”
“Oh, et y a tout ce qu’on peut mettre sur le cloud aussi.”
“Et euh… Les ressources ça rentre en compte ?”

Vous l’aurez compris, quand on parle de stockage sur mobile, et en particulier sur Android, ce n’est pas si évident que sur serveur. Il existe une multitude de moyens et d’endroits pour stocker une donnée. Et je ne parle que de moyens internes, même pas du cloud. La base de données n’est pas systématique, d’autres méthodes existent et peuvent se révéler bien plus utiles.

Et puis, il y a le fait qu’une application mobile peut devoir gérer des données très variées, avec des origines et des besoins différents, provenant du réseau, d’une autre application, étant une image, un PDF, un fichier JSON…

Du coup, ce n’est quand même pas toujours évident de savoir bien gérer le stockage de ses données…
Vous devinez quel est le but de cet article ?

Remise en contexte

Commençons par un petit rappel qui n’est jamais inutile : vous êtes sur mobile. Vous avez des ressources limitées, que ce soit en termes de stockage, de puissance de calcul, d’accès au réseau, de bande passante ou autre. Optimiser son application sur mobile est très important. Sur votre propre téléphone, combien d’applications désinstallez-vous parce qu’elles prennent trop d’espace ? Parce qu’elles mettent trop de temps à afficher vos données ? Parce qu’elles vident votre batterie en un clin d’œil ?
L’optimisation du stockage n’est pas un luxe, c’est un enjeu important sous Android. Même si on est très loin d’égaler la quantité de données traitées par un serveur (au contraire, on essayera d’en avoir le moins possible), cette optimisation peut faire la différence entre une application installée sur le long terme ou le court terme.

Ceci posé… Dédramatisons. Ces considérations ne sont valables que pour des applications assez volumineuses. Peu importe votre méthode de stockage, si vous n’avez que quelques catégories de données et n’en conservez que peu, ça passera très bien. C’est à partir du moment où votre application grossit que ça se complique. Et qu’il faut adopter de bonnes pratiques de gestion des données, pour éviter le débordement.

Il existe par contre un aspect de la gestion des données auquel vous ne pouvez pas couper : la sauvegarde des données réseaux. A partir du moment où vous faites appel à des webservices, il vous faudra mettre en place un mécanisme de conservation des données pour limiter le nombre d’appels ainsi que permettre d’accéder à ces données hors-ligne (si vous voulez en savoir plus savoir sur les webservices et comment les appeler correctement, voici un article qui en parle.
Dès lors, savoir bien stocker ses données devient essentiel pour avoir une application optimisée.

Comment stocker des données sous Android ?

Passons en revue les différentes options de stockage de données qui existent sous Android, telles que la documentation les décrit.

L’organisation des dossiers de l’application

Le système Android met à disposition de chaque application un certain nombre de dossiers où le développeur peut sauvegarder des fichiers, peu importe leur nature (fichier texte ou binaire) ou ses bases de données.
Un résumé des principales zones de stockage pour nos fichiers est ici intéressant à faire pour la suite.

Si vous voulez savoir quelles sont les autres méthodes disponibles, je vous recommande de jeter un œil à la documentation.

Le stockage interne

Le stockage interne correspond à un stockage dans la mémoire interne du device. Les fichiers y sont privés et seule l’application peut y avoir accès, à moins d’utiliser un Content Provider.

  • context.getFilesDir()
    chemin d’accès : /data/data/{my_package}/files
    Seule l’application gère l’espace disponible.

  • context.getCacheDir()
    chemin d’accès : /data/data/{my_package}/cache
    Les fichiers peuvent être supprimés par le système ou des applications tierces pour libérer de l’espace.

Le stockage externe

Le stockage externe est un stockage qui s’effectue dans une mémoire externe au device, le plus souvent sur une carte SD.
L’avantage du stockage externe est qu’il permet un stockage souvent plus important. Un utilisateur préfèrera voir ses données stockées sur sa carde SD vierge que sur une mémoire interne déjà fortement sollicitée.
Les fichiers y sont protégés, le Media Provider ne peut pas y accéder mais d’autres applications peuvent y avoir accès.

Le répertoire lié à la carte SD varie en fonction du constructeur du device (samsung, LG etc.).
En l’absence de carte SD, la plupart des devices ont un ou plusieurs emplacements externes virtuels souvent appelés “sdcard0”, “sdcard1” etc, qui permettent d’utiliser ce mode de stockage malgré l’absence de carte.

  • context.getExternalFilesDir(null)
    chemin d’accès : /storage/{sd_card}/Android/data/{my_package}/files
    L’application seule gère l’espace disponible.
    Note : Le paramètre de la méthode permet d’indiquer un sous-répertoire de ce dossier (décrit par les constantes de Context : DIRECTORY_ALARMS, DIRECTORY_MUSIC etc.)

  • context.getExternalCacheDir()
    chemin d’accès : /storage/{sd_card}/Android/data/{my_package}/cache
    Les fichiers peuvent être supprimés par le système ou des applications tierces pour libérer de l’espace.

  • Environment.getExternalStoragePublicDirectory(directory)
    chemin d’accès : /storage/{sd_card}/{directory}
    Dossiers publics servant à regrouper les médias communs pour l’utilisateur (musique, vidéo, photos…). Contrairement aux autres méthodes, les fichiers y sont entièrement publics, sont accessibles par le Media Provider et ne sont pas effacés à la désinstallation.
    Note : Le paramètre de la méthode permet d’indiquer le dossier où sera enregistré le média (décrit par les constantes de Context : DIRECTORY_ALARMS, DIRECTORY_MUSIC etc.)

Android 6.0 et l’“Adoptable Storage”
Une des nouveautés d’Android 6.0 est l’intégration du stockage “adoptable”. Le principe est qu’Android peut formatter et encrypter la carte SD pour la lier au fonctionnement du device et que cette carte soit considérée comme un stockage interne. Cependant, à l’heure actuelle très peu de devices intègrent cette fonctionnalité.

Les assets / resources

Certains l’auront noté, je n’ai parlé que de stockage “éditable” jusqu’ici, de stockage manipulable en lecture ET en écriture.

Les données situées dans les assets et dans les resources appartiennent à un mode de stockage encore différent. Elles n’existent que dans l’APK de l’application et ont la particularité de ne pas être modifiables, agissant comme des données statiques uniquement exploitables en lecture. Leur intérêt réside dans la vitesse à laquelle ces informations peuvent être consultées, et surtout l’assurance que ces données soient immuables et installées d’office avec l’application.

Les méthodes de stockage

Jusqu’ici on a parlé que des emplacements de stockage. Mais il est intéressant de voir également quelle sont les différentes méthodes de stockage possible sous Android.

SharedPreferences

Les SharedPreferences permettent d’enregistrer des paires clé / valeur de données. Elles sont adaptées pour la conservation de paramètres de configuration, utilisateur ou interne. Par ailleurs, il existe une Activity, appelée PreferenceActivity qui se synchronise très bien avec le contenu d’une instance de SharedPreference, ce qui en fait le candidat idéal pour la gestion des paramètres utilisateur.
Les SharedPreferences sont uniquement stockées dans les dossiers internes (sous data/data/{mypackage}).

Base de données

Android permet d’utiliser une base de données de type SQLite. Elle permet l’intégration de nombreuses bibliothèques de traitement (ORM notamment) et est particulièrement indiquée pour gérer des données structurées.

Par défaut, une base de données est située dans le répertoire de stockage interne, mais il peut être intéressant de la placer ailleurs dans certains cas (stockage externe pour une base de données très volumineuse, par exemple, ou bien laisser le choix à l’utilisateur).

Si l’on possède des données structurées que l’on souhaite avoir à la création de l’application, il est possible d’avoir une base de données en lecture seule dans les assets. Il faudra en copier le contenu dans une autre base de données pour pouvoir la manipuler. Il s’agit d’une méthode souvent utilisée pour définir la structure de la base de données principale (éditable), avec l’aide de la classe SQLiteOpenHelper.

Enfin un point important à noter : une base de données peut potentiellement être supprimée n’importe quand. En effet, lorsque l’utilisateur décide de vider son cache ou de supprimer ses données, il supprime la base de données présente dans le(s) répertoire(s) concerné(s) (interne et externe).

Fichiers

Les fichiers sont la structure de gestion de données la plus simple à comprendre. Ils peuvent être binaires (image, musique, pdf, vidéo…) ou textuels (page html, JSON, XML etc.), et peuvent être enregistrés dans n’importe quel emplacement.

Que faire de ses données ?

Les critères de distinction des données

Enfonçons une porte ouverte : comment définir ce qu’est une donnée ? Ça peut être une image, un texte, être structuré ou non, peut provenir du réseau comme exister dès le lancement de l’application, peut-être de quelques octets ou de plusieurs mégaoctets…
En bref : une donnée peut être tout et n’importe quoi. Chaque donnée est différente et surtout, n’a pas les mêmes besoins en fonction du contexte. Certaines devront être mises à jour régulièrement ou seront souvent manipulées dans le code, ou encore ni l’un ni l’autre.

Il devient dès lors important de mettre en place une forme de discrimination des données, et d’identifier les critères importants pour les qualifier. On peut déjà en identifier plusieurs :

  • L’origine : la donnée provient-elle du réseau ? D’une autre application ? Est-elle possédée au lancement ? Calculée ?
  • La nature : Est-ce qu’il s’agit de données primitives (texte, booléen, entier) ? D’une image, d’une vidéo ?
  • La mise à jour : la donnée est-elle mise à jour régulièrement ?
  • L’externalisation : La donnée sert-elle potentiellement à d’autres applications ?
  • L’utilisation : la donnée est-elle utilisée régulièrement par l’application ?
  • Les relations : La donnée est-elle relationnelle ?
  • La structure : la donnée est-elle structurée (JSON/XML par exemple) ?
  • La taille : la donnée est-elle volumineuse ?
  • L’indexation : la donnée est-elle utilisée comme une ressource (présente dans l’index du R) ?

Dans ces quelques critères, on peut d’ores et déjà distinguer deux catégories :

  • Ce qu’est la donnée (nature, taille, structure et relations)
  • Ce qui manipule la donnée (origine, mise à jour, utilisation, externalisation et indexation)

Cette division en deux catégories n’est pas innocente. En effet, les critères de ces deux catégories agiront respectivement sur la méthode de stockage et l’emplacement de la donnée.

Répartir ses données par critère

Voyons donc comment ces deux catégories de critères agissent sur la structuration des données.

Afin de vous donner une idée, voici une proposition de schéma de répartition des données, avec les différents moyens et emplacements de stockage sous Android.

Je précise qu’il s’agit d’une proposition basée sur des cas généraux. Il peut très bien y avoir des cas où ces diagrammes ne s’appliquent pas. Stocker des données de configuration triviales dans un fichier, par exemple, peut avoir un intérêt dans certaines circonstances.

Où placer sa donnée ?

Quel placement pour sa donnée ?

Un exemple parlant bien mieux qu’un long discours, essayons d’appliquer ces schémas sur un cas pratique.

Un cas concret : une application sur des actualités

Imaginons un instant que vous arriviez dans une nouvelle société qui veut créer une application Android. Cette application doit afficher les nombreuses actualités de la société à l’utilisateur, de façon régulière et fluide. On vous demande votre avis sur la manière de stocker certaines données qui existeront dans l’application :

  1. Les actualités elles-mêmes, reçues par le biais d’un webservice qui renvoie la liste d’objets au format JSON.
  2. La liste des actualités préférées de l’utilisateur, qu’il peut consulter au format PDF depuis une autre application (Google Books par exemple).
  3. Les images relatives aux actualités téléchargées.
  4. Les préférences de l’utilisateur sur l’envoi ou non de notifications et sur la fréquence des mises à jour.
  5. La configuration faite par l’utilisateur sur les actualités qu’il veut voir ou ne pas voir.
  6. Une vidéo d’ouverture qui présente les dernières nouveautés de l’application.
  7. Les actualités archivés, demandées par l’utilisateur par un webservice, potentiellement sur plusieurs années et d’une taille importante.

Analysons chaque donnée et tentons d’appliquer notre schéma précédent :

1) Les actualités : Il s’agit d’une donnée assez claire à analyser : textuelle, structurée et relationnelle, provenant du réseau. Sa place est dans une base de données située dans les fichiers internes. La base de données permet de réutiliser la donnée et de la combiner avec d’autres sources. Le stockage dans les fichiers internes (data/data/{mypackage}/files) assure le verrouillage de ces données et le fait qu’elles ne seront pas supprimées par le système pour faire de la place.

2) Les actualités favoris : ici c’est plus particulier : on doit pouvoir consulter les actualités à l’extérieur au format PDF. Il s’agira d’un fichier placé dans les fichiers externes. On préfèrera ce stockage plutôt que le stockage en cache car un favori utilisateur peut rester longtemps.

3) Les images d’actualités : les images sont ici des fichiers placés dans le cache interne. Même si les images sont liées aux actualités, elles ne sont ni structurées ni relationnelles (elles n’ont qu’une relation 1-1 avec une actualité). On les place dans le cache car l’affichage des actualités varie régulièrement. L’image n’est nécessaire que pendant la durée de vie de l’actualité, qui est souvent courte. Enfin, on la placera dans le stockage interne car elle n’a pas d’intérêt pour d’autres applications.

4) Les préférences : ce sont des données de configuration triviales, non-associées à des données existantes, elles iront mieux dans les SharedPreferences (qui ne peuvent exister que dans les fichiers interne pour rappel).

5) La configuration des actualités : Bien qu’il s’agisse de données de configuration triviales, elles sont avant tout relationnelles avec les actualités (relation 1-N). Dans ce cas-là, il est plus intéressant de les placer dans la même base de données que les actualités. De la sorte, on pourra effectuer une seule requête pour récupérer toutes les actualités concernées par la configuration utilisateur.

6) La vidéo d’ouverture : les vidéos sont, au même titre que les musiques, des médias que l’API Android manipule à l’aide de vues particulières (SurfaceView, VideoView, MediaPlayer etc.). Afin d’être utilisables dans ces vues, ces médias ont besoin d’être indexés dans les ressources, et donc le fichier vidéo doit être placé dans le répertoire “raw” des ressources.

7) Les actualités archivées : On est face à une importante quantité de données. Les actualités sont toujours structurées et relationnelles, donc une base de données, mais cette fois on les placera dans un stockage de fichiers externes. L’intérêt est d’offrir à l’utilisateur un support de stockage plus important pour conserver cette quantité de données. De plus, il s’agit de données non-essentielles, qui rendent le côté non-permanent de ce stockage moins gênant.

Conclusion

Vous l’aurez compris, Android offre une multitude de possibilités pour stocker ses données. Tellement qu’il est parfois difficile de savoir où placer ses données et avec quel moyen.

Avec cet article, j’espère vous avoir fourni quelques clés pour organiser au mieux vos données. Il ne s’agit pas ici de donner des règles absolues, mais quelques indications à ceux qui peuvent être un peu perdus façe au nombre de possibilités.

Il reste un point que l’on a tout juste effleuré ici : la sauvegarde des données réseaux. De manière générale même : comment préparer son code pour gérer efficacement cette sauvegarde ?