Lancement d’activités et de sous-activités
Activités paires et sous-activités
Lorsque vous décidez de lancer une activité, une question essentielle à laquelle vous devez répondre est : « Est-ce que mon activité a besoin de savoir quand se termine l’activité qu’elle a lancée ? » Supposons par exemple que vous vouliez créer une activité pour collecter des informations d’authentification pour un service web auquel vous vous connectez – vous devrez peutêtre vous authentifier avec OpenID1 pour utiliser un service OAuth2. En ce cas, votre activité principale devra savoir quand se termine l’authentification pour pouvoir commencer à utiliser le service web. Imaginons maintenant une application de courrier électronique Android. Lorsque l’utilisateur décide de visualiser un fichier attaché, ni vous ni l’utilisateur ne s’attend à ce que l’activité principale sache quand cette visualisation se terminera. Dans le premier scénario, l’activité lancée est clairement subordonnée à l’activité qui l’a lancée. La première sera donc sûrement lancée comme une sous-activité, ce qui signifie que la seconde sera prévenue de la fin de son activité fille. Dans le second scénario, l’activité lancée est plutôt un « pair » de l’activité qui l’a lancée. Elle sera donc plutôt lancée comme une activité classique. Votre activité ne sera pas informée de la fin de sa « fille » mais, encore une fois, elle n’a pas vraiment besoin de le savoir. Démarrage Pour démarrer une activité, il faut une intention et choisir comment la lancer. Création d’une intention Comme on l’a expliqué au Chapitre 1, les intentions encapsulent une requête pour une activité ou une demande adressée à un autre récepteur d’intention, afin qu’il réalise une certaine tâche. Si l’activité que vous comptez lancer vous appartient, il peut être plus simple de créer une intention explicite, nommant le composant à lancer. À partir de votre activité, vous pourriez par exemple créer une intention de la façon suivante : new Intent(this, HelpActivity.class); Cette instruction indique que vous voulez lancer HelpActivity. Vous pourriez également créer une intention pour une Uri donnée, demandant une action particulière : Uri uri=Uri.parse(« geo: » + lat.toString() + « , » + lon.toString()); Intent i=new Intent(Intent.ACTION_VIEW, uri); Ici, à partir de la latitude et de la longitude d’une position (respectivement lat et lon), nous construisons une Uri de schéma geo et nous créons une intention demandant de l’afficher (ACTION_VIEW). Faire appel Lorsque l’on dispose de l’intention, il faut la passer à Android et récupérer l’activité fille à lancer. Quatre choix sont alors possibles : ● Le plus simple consiste à appeler startActivity() en lui passant l’intention – Android recherchera l’activité qui correspond le mieux et lui passera l’intention pour qu’elle la traite. Votre activité ne sera pas prévenue de la fin de l’activité fille. ● Vous pouvez appeler startActivityForResult() en lui passant l’intention et un identifiant (unique pour l’activité appelante). Android recherchera l’activité qui correspond le mieux et lui passera l’intention. Votre activité sera prévenue par la méthode de rappel onActivityResult() de la fin de l’activité fille (voir plus loin). ● Vous pouvez appeler sendBroadcast(). Dans ce cas, Android passera l’intention à tous les BroadcastReceiver enregistrés qui pourraient vouloir cette intention, pas uniquement à celui qui correspond le mieux. ● Vous pouvez appeler sendOrderedBroadcast(). Android passera alors l’intention à tous les BroadcastReceiver candidats, chacun leur tour – si l’un deux « consomme » l’intention, les autres candidats ne sont pas prévenus. La plupart du temps, vous utiliserez startActivity() ou startActivityForResult() – les intentions diffusées sont plutôt lancées par le système Android lui-même. Comme on l’a indiqué, vous pouvez implémenter la méthode de rappel onActivityResult() lorsque vous utilisez startActivityForResult(), afin d’être prévenu de la fin de l’activité fille. Cette méthode reçoit l’identifiant unique fourni à startActivityForResult() pour que vous puissiez savoir quelle est l’activité qui s’est terminée. Vous récupérez également : L’art du développement Android ● Le code résultat de l’activité fille qui a appelé setResult(). Généralement, ce code vaut RESULT_OK ou RESULT_CANCELLED, bien que vous puissiez créer vos propres codes (choisissez un entier à partir de la valeur RESULT_FIRST_USER). ● Un objet String optionnel contenant des données du résultat, comme une URL vers une ressource interne ou externe – une intention ACTION_PICK se sert généralement de cette chaîne pour renvoyer le contenu sélectionné. ● Un objet Bundle optionnel contenant des informations supplémentaires autres que le code résultat et la chaîne de données. Pour mieux comprendre le lancement d’une activité paire, examinons le projet Activities/Launch.
Navigation avec onglets
La navigation par onglet est l’une des principales fonctionnalités des navigateurs web actuels : grâce à elle, une même fenêtre peut afficher plusieurs pages réparties dans une série d’onglets. Sur un terminal mobile, cela a moins d’intérêt car on gaspillerait la précieuse surface de l’écran pour afficher les onglets eux-mêmes. Toutefois, pour les besoins de la démonstration, nous montrerons comment créer ce genre de navigateur, en utilisant TabActivity et les intentions. Au Chapitre 10, nous avons vu qu’un onglet pouvait contenir une vue ou une activité. Dans ce dernier cas, vous devez fournir une intention qui lancera l’activité souhaitée ; le framework de gestion des onglets placera alors l’interface utilisateur de cette activité dans l’onglet. Votre premier instinct pourrait être d’utiliser une Uri http: comme nous l’avions fait avec une Uri geo: dans l’exemple précédent : Intent i=new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(« http://commonsware.com »)); Vous pourriez ainsi utiliser le navigateur intégré et disposer de toutes ses fonctionnalités. Malheureusement, cela ne marche pas car, pour des raisons de sécurité, vous ne pouvez pas héberger les activités d’autres applications dans vos onglets – uniquement vos propres activités. Nous allons donc dépoussiérer nos démonstrations de WebView du Chapitre 13 pour créer le projet Activities/IntentTab. Voici le code source de l’activité principale, celle qui héberge le TabView : public class IntentTabDemo extends TabActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TabHost host=getTabHost(); host.addTab(host.newTabSpec(« un ») .setIndicator(« CW ») .setContent(new Intent(this, CWBrowser.class))); host.addTab(host.newTabSpec(« deux ») .setIndicator(« Android ») .setContent(new Intent(this, AndroidBrowser.class))); } } Comme vous pouvez le constater, notre classe hérite de TabActivity : nous n’avons donc pas besoin de créer un fichier de description XML – TabActivity s’en occupe pour nous. L’art du développement Android Nous nous contentons d’accéder au TabHost et de lui ajouter deux onglets, chacun précisant une intention qui fait directement référence à une autre classe. Ici, nos deux onglets hébergeront respectivement un CWBrowser et un AndroidBrowser. Ces activités sont de simples variantes de nos précédents exemples de navigateurs : public class CWBrowser extends Activity { WebView browser; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); browser=new WebView(this); setContentView(browser); browser.loadUrl(« http://commonsware.com »); } } public class AndroidBrowser extends Activity { WebView browser; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); browser=new WebView(this); setContentView(browser); browser.loadUrl(« http://code.google.com/android »); } } Tous les deux chargent simplement une URL différente dans le navigateur : la page d’accueil de CommonsWare dans l’un (voir Figure 24.3), celle d’Android dans l’autre (voir Figure 24.4). Le résultat montre l’aspect qu’aurait un navigateur à onglets avec Android. L’utilisation de sous-classes différentes pour chaque page cible est plutôt onéreuse. À la place, nous aurions pu empaqueter l’URL pour qu’elle s’ouvre comme un « extra » dans une intention et utiliser cette intention pour créer une activité BrowserTab généraliste qui extrairait l’URL de cet « extra » afin de l’utiliser. Cette approche est laissée en exercice au lecteur.