studio - programmation android eyrolles pdf




Meilleure pratique pour conserver les données en mémoire et dans la base de données en même temps sur Android (2)

Nous concevons une application Android qui a beaucoup de données ("clients", "produits", "commandes" ...), et nous ne voulons pas interroger SQLite chaque fois que nous avons besoin d'un enregistrement. Nous voulons éviter d'interroger la base de données autant que possible, nous avons donc décidé de garder certaines données toujours en mémoire.

Notre idée initiale est de créer deux classes simples:

  1. "MemoryRecord": une classe qui contient essentiellement un tableau d'objets (string, int, double, datetime, etc ...), qui sont les données d'un enregistrement de table, et toutes les méthodes pour obtenir ces données dans / hors de cette tableau.

  2. "MemoryTable": une classe qui contiendra essentiellement une carte de [Key, MemoryRecord] et toutes les méthodes pour manipuler cette Map et insérer / mettre à jour / supprimer un enregistrement dans / depuis la base de données.

Ces classes seront dérivées à chaque type de table que nous avons dans la base de données. Bien sûr, il existe d'autres méthodes utiles non énumérées ci-dessus, mais elles ne sont pas importantes à ce stade.

Ainsi, au démarrage de l'application, nous chargerons ces tables d'une base de données SQLite en mémoire en utilisant ces classes, et chaque fois que nous aurons besoin de changer certaines données, nous changerons en mémoire et les publierons dans la base de données juste après.

Mais, nous voulons de l'aide / des conseils de votre part. Pouvez-vous suggérer quelque chose de plus simple ou efficace pour mettre en œuvre une telle chose? Ou peut-être quelques classes existantes qui le font déjà pour nous?

Je comprends ce que vous essayez de me montrer, et je vous en remercie.

Mais, disons que nous avons une table avec 2000 enregistrements, et j'ai besoin de lister ces enregistrements. Pour chacun d'entre eux, je dois interroger 30 autres tables (certaines avec 1000 enregistrements, d'autres avec 10 enregistrements) pour ajouter des informations supplémentaires dans la liste, et ce pendant qu'il "vole" (et comme vous le savez, nous devons être très rapides à ce moment là).

Maintenant, vous allez dire: "construisez simplement votre requête principale avec toutes ces" jointures ", et apportez tout ce dont vous avez besoin en une étape: SQLite peut être très rapide, si votre base de données est bien conçue, etc ...".

OK, mais cette requête deviendra très compliquée et sûre, même si SQLite est très rapide, il sera "trop" lent (2 à 4 secondes, comme je l'ai confirmé, et ce n'est pas un temps acceptable pour nous).

Un autre complicateur est que, en fonction de l'interaction de l'utilisateur, nous devons «re-interroger» tous les enregistrements, car les tables impliquées ne sont pas les mêmes et nous devons «rejoindre» un autre ensemble de tables.

Ainsi, une alternative est de n'apporter que les enregistrements principaux (cela ne changera jamais, peu importe ce que l'utilisateur fait ou veut) sans jointure (c'est très rapide!) Et d'interroger les autres tables chaque fois que nous voulons des données. Notez que sur la table avec 10 enregistrements seulement, nous allons chercher les mêmes enregistrements plusieurs fois et plusieurs fois. Dans ce cas, c'est une perte de temps, car peu importe SQLite rapide, il sera toujours plus coûteux de faire des requêtes, des curseurs, des fetchs, etc ... que de simplement saisir l'enregistrement d'une sorte de "cache mémoire". Je tiens à préciser que nous n'avons pas l'intention de conserver toutes les données en mémoire, seulement quelques tables que nous interrogeons très souvent.

Et nous sommes arrivés à la question initiale: Quelle est la meilleure façon de "mettre en cache" ces enregistrements? J'aime vraiment axer la discussion sur cela et non pas "pourquoi avez-vous besoin de mettre des données en cache?"


Le problème avec un cache mémoire est bien entendu que vous devez le synchroniser avec la base de données. J'ai trouvé que l'interrogation de la base de données est en fait assez rapide, et vous pouvez pré-optimiser ici. J'ai fait beaucoup de tests sur des requêtes avec différents ensembles de données et ils ne prennent jamais plus de 10-20 ms.

Tout dépend de la façon dont vous utilisez les données, bien sûr. ListViews sont assez bien optimisés pour gérer un grand nombre de lignes (j'ai testé dans la gamme 5000 sans problèmes réels).

Si vous souhaitez conserver le cache mémoire, vous pouvez demander à la base de données de notifier le cache lorsque son contenu est modifié, puis de mettre à jour le cache. De cette façon, n'importe qui peut mettre à jour la base de données sans connaître la mise en cache. En outre, si vous construisez un ContentProvider sur votre base de données, vous pouvez utiliser ContentResolver pour vous notifier des modifications si vous vous inscrivez en utilisant registerContentObserver.


La grande majorité des applications sur la plateforme (contacts, Email, Gmail, calendrier, etc.) ne le font pas. Certains d'entre eux ont des schémas de base de données extrêmement compliqués avec potentiellement une grande quantité de données et n'ont pas besoin de le faire. Ce que vous proposez de faire vous causera une douleur énorme , sans gain net.

Vous devez d'abord vous concentrer sur la conception de votre base de données et de votre schéma afin de pouvoir effectuer des requêtes efficaces. Il y a deux raisons principales que je peux considérer pour que l'accès à la base de données soit lent:

  • Vous avez vraiment des schémas de données compliqués.
  • Vous avez une très grande quantité de données.

Si vous allez avoir beaucoup de données, vous ne pouvez pas vous permettre de tout garder en mémoire de toute façon, donc c'est une impasse. Si vous avez des structures compliquées, vous bénéficieriez dans les deux cas d'une optimisation pour améliorer les performances. Dans les deux cas, votre schéma de base de données va être la clé de bonnes performances.

En fait, l'optimisation du schéma peut être un peu un art noir (et je ne suis pas expert en la matière), mais certaines choses à surveiller créent correctement des index sur les lignes que vous interrogerez, concevant des jointures pour prendre des chemins efficaces, etc. Je suis sûr qu'il y a beaucoup de gens qui peuvent vous aider dans ce domaine.

Vous pouvez également essayer de trouver la source de certaines bases de données de la plate-forme pour obtenir des idées sur la conception d'une bonne performance. Par exemple, la base de données Contacts (en particulier à partir de la version 2.0) est extrêmement compliquée et a beaucoup d'optimisations pour fournir de bonnes performances sur des données relativement volumineuses et des ensembles de données extensibles avec beaucoup de différents types de requêtes.

Mettre à jour:

Voici une bonne illustration de l'importance de l'optimisation de la base de données. Dans la base de données des fournisseurs de médias d'Android, une version plus récente de la plateforme a considérablement modifié le schéma pour ajouter de nouvelles fonctionnalités. Le code de mise à niveau pour modifier une base de données de médias existante vers le nouveau schéma peut prendre 8 minutes ou plus à exécuter.

Un ingénieur a fait une optimisation qui a réduit le temps de mise à niveau d'une vraie base de données de test de 8 minutes à 8 secondes. Une amélioration de la performance de 60x.

Quelle était cette optimisation?

Il s'agissait de créer un index temporaire, au moment de la mise à niveau, sur une colonne importante utilisée dans les opérations de mise à niveau. (Et puis supprimez-le lorsque vous avez terminé.) Donc, cette amélioration des performances 60x vient même si elle comprend également le temps nécessaire pour construire un index sur l'une des colonnes utilisées lors de la mise à niveau.

SQLite est l'une de ces choses où si vous savez ce que vous faites, il peut être remarquablement efficace. Et si vous ne faites pas attention à la façon dont vous l'utilisez, vous pouvez vous retrouver avec des performances misérables. Si vous rencontrez des problèmes de performances, vous pouvez parier que vous pouvez les corriger en améliorant la façon dont vous utilisez SQLite.





design-guidelines