Concevoir pour la fluidité

Même si votre application est rapide et réactive, certaines décisions de conception peuvent toujours causer des problèmes aux utilisateurs, en raison d'interactions non planifiées avec d'autres applications ou boîtes de dialogue, d'une perte accidentelle de données, d'un blocage involontaire, etc. Pour éviter ces problèmes, il est utile de comprendre le contexte dans lequel vos applications s'exécutent et les interactions système qui peuvent affecter votre application. En résumé, vous devez vous efforcer de développer une application qui interagit de manière transparente avec le système et avec d'autres applications.

Un problème de transparence courant se produit lorsque le processus d'arrière-plan d'une application, par exemple un service ou un broadcast receiver, affiche une boîte de dialogue en réponse à un événement. Ce comportement peut sembler inoffensif, en particulier lorsque vous compilez et testez votre application de manière isolée sur l'émulateur. Toutefois, lorsque votre application est exécutée sur un appareil réel, elle peut ne pas être ciblée par l'utilisateur au moment où le processus en arrière-plan affiche la boîte de dialogue. Votre application peut donc afficher une boîte de dialogue derrière l'application active, ou s'éloigner de l'application actuelle et afficher la boîte de dialogue devant ce que faisait l'utilisateur (comme composer un appel téléphonique, par exemple). Ce comportement ne fonctionnerait ni pour votre application, ni pour l'utilisateur.

Pour éviter ces problèmes, votre application doit utiliser le composant système approprié pour avertir l'utilisateur : les classes Notification. À l'aide de notifications, votre application peut signaler à l'utilisateur qu'un événement s'est produit, en affichant une icône dans la barre d'état au lieu de se concentrer et de l'interrompre.

Autre exemple de problème d'fluidité : lorsqu'une activité perd par inadvertance un état ou des données utilisateur, car elle n'implémente pas correctement onPause() et d'autres méthodes de cycle de vie. Si votre application expose des données destinées à être utilisées par d'autres applications, vous devez les exposer via ContentProvider plutôt que via une base de données ou un fichier brut lisibles par tous (par exemple).

Ces exemples ont un point en commun : ils impliquent une bonne coopération avec le système et d'autres applications. Le système Android est conçu pour traiter les applications comme une sorte de fédération de composants faiblement couplés, plutôt que comme des fragments de code par boîte noire. Cela vous permet, en tant que développeur, de visualiser l'ensemble du système comme une fédération encore plus grande de ces composants. Vous bénéficiez ainsi d'une intégration propre et fluide à d'autres applications. Vous devez donc concevoir votre propre code pour en faciliter l'intégration.

Ce document décrit les problèmes courants de transparence et explique comment les éviter.

Ne pas supprimer les données

N'oubliez pas qu'Android est une plate-forme mobile. Même si cela peut sembler évident, n'oubliez pas qu'une autre activité (telle que l'application "Appel téléphonique entrant") peut apparaître à tout moment sur votre propre activité. Cette action déclenchera les méthodes onSaveInstanceState() et onPause(), et entraînera probablement la fermeture de votre application.

Si l'utilisateur modifiait des données dans votre application lorsque l'autre activité est apparue, votre application perd probablement ces données lorsqu'elle est fermée. À moins que vous n'enregistriez d'abord le travail en cours. C'est exactement ce que fait Android: les applications Android qui acceptent ou modifient des entrées doivent remplacer la méthode onSaveInstanceState() et enregistrer leur état de manière appropriée. Lorsque l'utilisateur revient dans l'application, il doit pouvoir récupérer ses données.

Une application de messagerie constitue un bon exemple d'utilisation de ce comportement. Si l'utilisateur rédigeait un e-mail au démarrage d'une autre activité, l'application doit enregistrer l'e-mail en cours de traitement en tant que brouillon.

Ne pas exposer de données brutes

Si vous ne marcheriez pas dans la rue en sous-vêtements, vos données non plus. Bien qu'il soit possible de mettre certains types d'applications à la disposition du monde entier, ce n'est généralement pas la meilleure idée. L'exposition de données brutes nécessite que d'autres applications comprennent le format de vos données. Si vous modifiez ce format, toutes les autres applications qui ne sont pas mises à jour de la même manière seront interrompues.

La méthode Android consiste à créer un ContentProvider pour exposer vos données à d'autres applications via une API propre, bien conçue et facile à gérer. L'utilisation d'un ContentProvider ressemble à l'insertion d'une interface de langage Java pour scinder et composant deux éléments de code étroitement couplés. Cela signifie que vous pourrez modifier le format interne de vos données sans modifier l'interface exposée par ContentProvider, et ce sans affecter les autres applications.

Ne pas interrompre l'utilisateur

Si l'utilisateur exécute une application (telle que l'application Téléphone pendant un appel), il est fort probable qu'il l'ait fait intentionnellement. C'est pourquoi vous devez éviter de générer des activités, sauf en réponse directe à l'entrée utilisateur de l'activité actuelle.

Autrement dit, n'appelez pas startActivity() à partir de BroadcastReceivers ou de services s'exécutant en arrière-plan. Cela interromprait l'application en cours d'exécution et gênerait l'utilisateur. Pire encore, votre activité peut devenir un "bandit de frappe" et recevoir une partie de l'entrée que l'utilisateur entreprend dans l'activité précédente. Selon les actions de votre application, cela pourrait être une mauvaise nouvelle.

Au lieu de générer des interfaces utilisateur d'activité directement en arrière-plan, vous devez utiliser le gestionnaire de notifications pour définir les notifications. Ceux-ci apparaissent dans la barre d'état, et l'utilisateur peut cliquer dessus à tout moment pour voir ce que votre application doit lui montrer.

(Notez que tout cela ne s'applique pas aux cas où votre propre activité est déjà au premier plan: dans ce cas, l'utilisateur s'attend à voir votre prochaine activité en réponse à une entrée.)

Vous avez beaucoup de choses à faire ? Dans un fil de discussion

Si votre application doit effectuer des calculs coûteux ou de longue durée, vous devez probablement la déplacer vers un thread. Cela empêchera l'affichage de la boîte de dialogue redoutable "L'application ne répond pas" à l'utilisateur. Le résultat ultime est la disparition brutale de votre application.

Par défaut, tout le code d'une activité ainsi que toutes ses vues s'exécutent dans le même thread. Il s'agit du même thread qui gère également les événements d'interface utilisateur. Par exemple, lorsque l'utilisateur appuie sur une touche, un événement de touche bas est ajouté à la file d'attente du thread principal de l'activité. Le système de gestionnaire d'événements doit retirer cet événement de la file d'attente et le gérer rapidement. Si ce n'est pas le cas, le système conclut au bout de quelques secondes que l'application est bloquée et propose de la fermer pour l'utilisateur.

Si vous avez du code de longue durée, si vous l'exécutez de manière intégrée dans votre activité, il s'exécutera sur le thread du gestionnaire d'événements, bloquant ainsi le gestionnaire d'événements. Cela retardera le traitement des entrées et l'affichage des boîtes de dialogue ANR. Pour éviter cela, déplacez vos calculs vers un thread. Ce document Concevoir pour la réactivité explique comment procéder.

Ne surchargez pas un seul écran d'activité.

Toute application utile aura probablement plusieurs écrans différents. Lorsque vous concevez les écrans de votre interface utilisateur, veillez à utiliser plusieurs instances d'objet Activity.

Selon votre environnement de développement, vous pouvez interpréter une activité comme s'il s'agissait d'un applet Java, car il s'agit du point d'entrée de votre application. Toutefois, ce n'est pas tout à fait exact. Lorsqu'une sous-classe d'applet est le point d'entrée unique d'un applet Java, une activité doit être considérée comme l'un des points d'entrée potentiellement multiples de votre application. La seule différence entre votre activité "principale" et toute autre activité est que l'activité "principale" est simplement la seule ayant exprimé un intérêt pour l'action "android.intent.action.MAIN" dans votre fichier AndroidManifest.xml.

Lorsque vous concevez votre application, considérez-la comme une fédération d'objets Activity. Cela rendra votre code beaucoup plus facile à gérer à long terme. C'est également un effet secondaire qui s'intègre parfaitement à l'historique des applications et au modèle "backstack" d'Android.

Étendre les thèmes système

En ce qui concerne l'apparence de l'interface utilisateur, il est important de l'harmoniser. Les utilisateurs sont pénibles par les applications qui contrastent avec l'interface utilisateur qu'ils attendent. Lorsque vous concevez une interface utilisateur, évitez autant que possible de lancer la vôtre. Utilisez plutôt un thème. Vous pouvez remplacer ou étendre les parties du thème nécessaires, mais au moins vous partez de la même base d'interface utilisateur que toutes les autres applications. Pour en savoir plus, consultez la section Styles et thèmes.

Concevez votre interface utilisateur pour qu'elle fonctionne avec plusieurs résolutions d'écran

La résolution d'écran varie selon les appareils Android. Certains peuvent même modifier les résolutions à la volée, par exemple en basculant en mode Paysage. Il est important de vous assurer que vos mises en page et vos drawables sont suffisamment flexibles pour s'afficher correctement sur divers écrans d'appareil.

Heureusement, cette opération est très simple. En bref, ce que vous devez faire est de fournir différentes versions de votre illustration (le cas échéant) pour les résolutions principales, puis de concevoir votre mise en page pour qu'elle s'adapte à différentes dimensions. (Par exemple, évitez d'utiliser des positions codées en dur et utilisez plutôt des mises en page relatives.) Si vous faites autant d'opérations, le système s'occupe du reste, et votre application s'affiche correctement sur n'importe quel appareil.

Supposer que le réseau est lent

Les appareils Android sont livrés avec différentes options de connectivité réseau. Tous disposent d'un certain niveau d'accès aux données, mais certains sont plus rapides que d'autres. Cependant, le plus petit dénominateur commun est GPRS, le service de données hors 3G pour les réseaux GSM. Même les appareils compatibles 3G passent beaucoup de temps sur des réseaux non 3G. Par conséquent, les réseaux lents resteront une réalité pendant longtemps.

C'est pourquoi vous devez toujours coder vos applications de manière à minimiser les accès réseau et la bande passante. Vous ne pouvez pas supposer que le réseau est rapide. Vous devez donc toujours prévoir qu'il sera lent. Si vos utilisateurs se trouvent sur des réseaux plus rapides, c'est parfait : leur expérience ne fera que s'améliorer. Cependant, il est préférable d'éviter le cas inverse: les applications qui sont utilisables une partie du temps, mais qui ralentissent frustrant le reste en fonction de l'endroit où se trouve l'utilisateur à un moment donné, sont susceptibles d'être impopulaires.

L'un des pièges potentiels ici est qu'il est très facile de tomber dans ce piège si vous utilisez l'émulateur, car celui-ci utilise la connexion réseau de votre ordinateur de bureau. Il est presque certain que ce sera beaucoup plus rapide qu'un réseau de téléphonie mobile. Vous devrez donc modifier les paramètres de l'émulateur qui simulent des débits réseau plus lents. Vous pouvez le faire dans Android Studio via AVD Manager ou via une option de ligne de commande au démarrage de l'émulateur.

Ne partez pas du principe que l'écran tactile ou le clavier

Android est compatible avec différents facteurs de forme de téléphone. C'est une manière sophistiquée de dire que certains appareils Android disposent d'un clavier "QWERTY" complet, tandis que d'autres ont une configuration à 40 touches, 12 touches ou même d'autres. De même, certains appareils sont équipés d'un écran tactile, mais ce n'est pas le cas pour beaucoup.

Gardez cela à l'esprit lorsque vous créez vos applications. Ne faites pas d'hypothèses sur des dispositions de clavier spécifiques, sauf si, bien sûr, vous souhaitez vraiment restreindre votre application afin qu'elle ne puisse être utilisée que sur ces appareils.

Préservez l'autonomie de la batterie de l'appareil

Un appareil mobile n'est pas très mobile s'il est constamment branché au mur. Les appareils mobiles fonctionnent sur batterie, et plus l'autonomie de la batterie est longue, plus tout le monde est heureux, en particulier l'utilisateur. Le processeur et la radio sont deux des plus grands consommateurs de puissance de la batterie. C'est pourquoi il est important d'écrire vos applications pour qu'elles effectuent le moins de travail possible et d'utiliser le réseau le moins souvent possible.

Pour réduire le temps de traitement de votre application, vous devez écrire un code efficace. Pour réduire la consommation d'énergie liée à l'utilisation du signal radio, veillez à gérer correctement les conditions d'erreur et à n'extraire que ce dont vous avez besoin. Par exemple, ne relancez pas constamment une opération réseau si l'une d'entre elles échoue. S'il a échoué une fois, c'est probablement parce que l'utilisateur n'a pas de réception. L'opération va probablement échouer à nouveau si vous essayez immédiatement. Tout ce que vous ferez, c'est de gaspiller la batterie.

Les utilisateurs sont assez intelligents: si votre programme est très énergique, vous pouvez compter sur eux. La seule chose dont vous pouvez être sûr à ce stade, c'est que votre programme ne restera pas très longtemps installé.