Jump to content

Architecture des services


®om

Recommended Posts

Bonjour,

Je comprends techniquement comment fonctionne les services (j'ai déjà utilisé plusieurs fois), mais je me pose des questions d'architecture pour faire "au mieux".

Généralement, dans une application, il y a un ensemble d'écrans et un ensemble d'actions à effectuer sur un serveur (envoyer un message, récupérer une liste de messages, supprimer un message, etc.).

Faut-il un service par action ? Un service avec toutes les actions ?

Faut-il fermer (stopSelf()) le service à chaque action ? Sinon, quand le fermer ?

De plus, dans quels cas privilégier un service sur une AsyncTask ? Par exemple, pour charger la liste des messages pour un écran donné, la question peut se poser.

Mettre de telles actions dans un AsyncTask me dérange, parce que la séparation entre la vue et le service est vraiment fine (souvent on voit une AsyncTask en tant que classe interne de l'activité).

Mais aussi techniquement, si l'action doit écrire dans une base de données (par exemple sur le retour de la réponse du serveur), qu'elle est dans une AsyncTask, et qu'avant que l'écriture soit terminée, l'activité est quittée, alors il ne reste plus aucune activité lancée, ni aucun service (par hypothèse) : le processus peut donc se faire tuer (kill -9) en plein milieu d'une écriture... (que ce soit très peu probable ou pas n'est pas la question)

Bref, comment construisez-vous vos applis qui possèdent des vues et qui récupèrent les données sur un serveur ?

Merci de vos avis.

Link to comment
Share on other sites

Généralement, dans une application, il y a un ensemble d'écrans et un ensemble d'actions à effectuer sur un serveur (envoyer un message, récupérer une liste de messages, supprimer un message, etc.).

Faut-il un service par action ? Un service avec toutes les actions ?

Faut-il fermer (stopSelf()) le service à chaque action ? Sinon, quand le fermer ?

Pour toutes ces actions, je ne créé pas de service. La question à se poser c'est : quel est l'intérêt de passer par un service ? Est-ce que je vais envoyer un message au serveur quand mon appli sera fermée ? Est-ce que je vais récupérer une liste de messages (sans doute pour les afficher) si mon appli est fermée ? etc, etc.

Pour toutes ces tâches, je n'ai pas besoin d'un service. Une AsyncTask suffit amplement (je continue l'argumentaire plus bas ^^).

Mettre de telles actions dans un AsyncTask me dérange, parce que la séparation entre la vue et le service est vraiment fine (souvent on voit une AsyncTask en tant que classe interne de l'activité).

Là, ce n'est pas un problème en termes de fonctionnement, par contre, c'est pas propre. Niveau maintenance, lisibilité du code, réutilisabilité de l'AsyncTask, ça se pose là :D Donc, oui, une AsyncTask doit (enfin, devrait) faire l'objet d'une classe "à part".

Mais aussi techniquement, si l'action doit écrire dans une base de données (par exemple sur le retour de la réponse du serveur), qu'elle est dans une AsyncTask, et qu'avant que l'écriture soit terminée, l'activité est quittée, alors il ne reste plus aucune activité lancée, ni aucun service (par hypothèse) : le processus peut donc se faire tuer (kill -9) en plein milieu d'une écriture... (que ce soit très peu probable ou pas n'est pas la question)

Là, c'est vrai que ça peut être sensible. Je dis "ça peut" car, c'est comme partout, chaque action doit être suffisamment bien codée pour que le cas d'une interruption ne soit pas critique.

Je m'explique. Si tu écris sur une base SQLite, c'est à toi de penser convenablement tes classes de gestion de bdd. L'utilisation des mécanismes de transaction, commit, rollback, etc (je ne creuse pas le sujet, je ne suis pas familier avec ^^) te permettent de contrecarrer une interruption inopinée. L'exemple sur une Activity de récupération d'infos serveur pour écriture en bdd :

(Je pars du principe que le onstop de l'activity fait un cancel sur toutes les AsyncTasks actives...)

- Activity lancée

- AsyncTask de récupération des infos serveur lancée

- Une fois terminée, cette dernière lance l'AsyncTask d'écriture en bdd

Si on kill avant la fin de la récupération des données, tant pis, on ne perd rien.

Si on kill pendant la phase d'écriture, pas de soucis non plus, le commit se fait en toute fin de processus (ok... Si l'appli est killé brutalement par une extinction du mobile par exctraction de batterie en plein dans le commit, ça risque de poser problème... Cependant, c'est un cas en marge car cela sort du périmètre de fonctionnement classique de l'OS. Je ne suis pas certain que ce dernier s'en sorte mieux s'il est en train d'écrire en base...). Et comme tu auras intelligemment codé ton AsyncTask, un cancel de celle-ci notifiera la classe de gestion de la base de stopper (celle-ci fera ce qu'elle a à faire, notifier l'arrêt de l'écriture, fermer la base proprement, etc).

C'est un exemple basique mais si chaque étape d'une action est sécurisée, il n'y a aucune raison que cela se passe mal.

Bref, comment construisez-vous vos applis qui possèdent des vues et qui récupèrent les données sur un serveur ?

Bref, je n'utilise des services que si cela se justifie (traitement n'impliquant pas d'afficher le résultat).

J'espère que ça t'aura aidé ;) (enfin, tu ne cherches pas vraiment d'aide mais plutôt un recueil d'expériences et d'avis :D )

A plus ;)

Link to comment
Share on other sites

Merci beaucoup de ta réponse.

Pour toutes ces actions, je ne créé pas de service. La question à se poser c'est : quel est l'intérêt de passer par un service ? Est-ce que je vais envoyer un message au serveur quand mon appli sera fermée ? Est-ce que je vais récupérer une liste de messages (sans doute pour les afficher) si mon appli est fermée ? etc, etc.

Pour moi, une activité veut "envoyer un message", "récupérer une liste de messages" ou "supprimer un message" : elle n'a pas à en connaître l'implémentation.

Pour l'envoi et la suppression de messages, on peut imaginer ajouter un mécanisme de réessai s'il y a des problèmes réseau (y compris quand l'activité est fermée). Je pense que l'ajout de cette fonctionnalité ne devrait en aucune manière impacter l'activité.

Pour la récupération de la liste de messages, l'intérêt est peut-être moindre, mais si je demande à charger des données, que le chargement prend 10s, et qu'au bout de 5s je veux quitter l'activité, je ne peux pas "rattraper" ma requête au serveur (elle est déjà partie), autant ne pas ignorer les résultats et les stocker en cache quand même lorsque je les recevrai (même si l'activité est déjà quittée). Comme ça quand je relance l'appli, les données sont là.

De plus, une AsyncTask pose problème si tu changes l'orientation de l'écran :

- j'envoie une requête de chargement au serveur

- avant sa réponse, je tourne l'écran, l'activité est reconstruite, il faut donc relancer une nouvelle AsyncTask et refaire la requête au serveur (la requête sera donc faite en double)

Utiliser les NonConfigurationInstances ne semble pas résoudre le problème : ça ne permet de sauvegarder que les données déjà récupérées.

Et supposons qu'on utilise un cache de données pour éviter de faire la même requête plusieurs fois.

  1. demande de chargement des données par l'activité
  2. vérification en cache si elles y sont déjà (supposons que non)
  3. demande de chargement des données au serveur
  4. réponse du serveur
  5. écriture des données en cache
  6. envoi des données à l'activité (par un ResultReceiver)

Si l'activité est relancée entre (1) et (5), le cache n'a pas rempli son rôle : la requête a été effectuée deux fois.

Avec un service, on peut s'apercevoir que la requête est la même que celle qui est en cours, et brancher le callback sur la requête déjà partie, et ça résout tous ces problèmes d'un coup (c'est ce que j'avais fait sur une appli).

permettent de contrecarrer une interruption inopinée

Justement, ici, il ne s'agit pas d'une interruption inopinée : pour Android, on n'a plus rien de "vivant" (plus d'activité, plus de service, juste un thread qui tourne mais qui n'est accroché à rien, donc c'est un empty process). Il est donc normal qu'il puisse le tuer quand il veut. Il faudrait un moyen pour lui indiquer que le process n'est pas en état "empty process", mais en priorité plus élevée, le temps qu'il ait fini d'écrire en base. Et pour cela, je ne vois pas d'autre solution que le service.

- Activity lancée

- AsyncTask de récupération des infos serveur lancée

- Une fois terminée, cette dernière lance l'AsyncTask d'écriture en bdd

C'est une possibilité intéressante (à part les remarques/questions ci-dessus). D'ailleurs, vu que l'écriture en bdd est totalement asynchrone (et qu'on n'a pas besoin de faire d'action dans l'UIThread), on pourrait utiliser un simple thread.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...