AIR Mobile – Application Pokémon (5) – Liste des Pokémon depuis la BDD SQLite
Dans les tutoriaux Flex précédents, on a vu comment ouvrir la base de données SQLite et comment lancer notre projet dans l'émulateur:
AIR Mobile – Application Pokémon (3) – Ouverture de la BDD SQLite
AIR Mobile – Application Pokémon (4) – Lancer l'application dans l’émulateur + debugger
On va maintenant travailler sur notre première vue et afficher la liste des pokémons. Pour cela, on va effectuer une requête SQL (SELECT) et afficher le résultat dans un composant List.
Effectuer le traitement au bon moment
Avant d'effectuer notre requête SELECT, il faut savoir à quel moment on va la faire. En effet, si vous avez suivi l'article sur le cycle de vie des View en Flex, vous savez que celle-ci propage des évènements lors de sa création et de sa destruction.
Les évènements qui vont nous intéresser sont:
- creationComplete : Propagé quand tous les composants de la vue (comme notre List) sont instanciés et accessible. La vue n'est pas encore affichée à l'écran mais vous pouvez la manipuler
- viewActivate : Propagé après "creationComplete", une fois que la transition entre les vues est terminée.
Alors lequel utiliser? Et bien cela dépend. En effet, si vous effectuez trop de traitement lors du "creationComplete", la transition de la vue va peut-être saccader. Mais en même temps, si vous faîtes votre traitement sur "viewActivate", il sera presque "trop tard" et si votre traitement est d'afficher / masquer des composants, votre vue va légèrement clignoter. A vous donc de voir et de choisir la meilleure solution, c'est à dire la plus adaptée à votre utilisation.
Pour cette première vue, ce n'est pas très important car en fait, la première vue n'arrive pas avec une transition. Que vous soyez sur "creationComplete" ou sur "viewActivate" ne fera donc que très peu de différence. Mais si on était sur une autre vue, sur laquelle on arrive par une transition, on aurait sûrement mis notre SELECT sur l'évènement "viewActivate" car nous effectuons nos requêtes en mode synchrone. Si nous l'avions ouverte en mode asynchrone, on aurait utilisé "creationComplete" plutôt. Voilà le genre de question qu'il faut se poser, souvent résolues par de rapides tests.
Récupérer la connexion SQL (SQLConnection)
Ouvrez donc le fichier "PokemonInfosHomeView.mxml" qui est notre première vue. Comme vous l'avez fait dans la 3eme partie du tutorial, ajouter un écouteur d'évènement sur "creationComplete" que vous allez appeler "onCComplete". De la même manière, laissez-vous guider par Flash Builder:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"
creationComplete="onCComplete(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function onCComplete(event:FlexEvent):void
{
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:View>
Première chose que l'on va faire dans onCComplete, on va récupérer la connexion SQL que l'on avait ouvert dans la partie 3 du tutorial. Notre connexion est conservée au niveau de l'application. Celle ci peut être accédée depuis n'importe quel endroit grâce à la variable static:
FlexGlobals.topLevelApplication
Pour éviter de récupérer à chaque fois la référence vers notre SQLConnection depuis notre application, on va conserver une référence directement dans notre vue:
import mx.core.FlexGlobals; import mx.events.FlexEvent; private var _sqlConnection:SQLConnection = null; protected function onCComplete(event:FlexEvent):void{ _sqlConnection = FlexGlobals.topLevelApplication.sqlConnection; }
Ajouter le composant List
Pour avoir un affichage visuel de notre liste de pokémons, on va ajouter un composant List. Pour une liste des composants (non exhaustive) des composants du SDK 4.5, je vous conseille de lire cet article:
AIR Mobile – Les composants et le thème Mobile Flex 4.5
Rendez-vous donc entre la fin du tag fx:Declaration et la fin du tag View puis tapez le caractère "<". Appuyez sur Ctrl+Espace et la liste des composants disponibles va s'afficher. Tapez "List" puis appuyez sur Entrée:
Appuyez sur Espace et la liste des propriétés du composant va s'afficher. Vous pouvez commencer à taper le nom des propriétés comme "width" ou "height" et valider par Entrée. Comme exercice, on va fixer les propriétés "width" et "height" à la valeur "100%". Cela signifie que notre liste va prendre toute la place offerte par son conteneur, la vue.
Une fois que vous avez terminé, fermez le tag avec un chevron fermant ">". Le tag XML </s:List> fermant la balise sera automatiquement ajouté:
<s:List width="100%" height="100%"> </s:List>
Le composant List et la propriété "dataProvider"
Notre composant List est un composant graphique permettant d'afficher de la donnée. Pour définir quelle donnée doit être affichée dans ce composant, on renseigne la propriété "dataProvider". Ce "dataProvider" est de type IList. Comme vous pouvez le voir dans la documentation, dans la partie "Implementors", les classes qui implémentent IList sont ArrayList, AsyncListView, ListCollectionView et les classes qui en héritent.
La classe qui est la plus souvent utilisée est la classe ArrayCollection, qui est un tableau de données (mais en mieux). Déclarons donc une variable dans la balise Script, de type ArrayCollection. N'oubliez pas la directive "import mx.collections.ArrayCollection;" en début de fichier, qui est automatiquement ajoutée si vous utilisée l'auto-complétion de Flash Builder (Ctrl+Espace):
private var _dp:ArrayCollection = null;
Maintenant, on va lier notre variable à la propriété "dataProvider". Pour cela, on va lier ces propriétés de manière dynamique par un mécanisme que l'on appelle "Binding". En déclarant notre variable comme "Bindable", la liste pourra être informée de manière dynamique de tout changement de la propriété. Ainsi, si vous supprimez un élément de "_dp", la List sera automatiquement mise à jour.
Pour déclarer une variable comme Bindable, il vous suffit de rajouter un metatag juste avant nommé "[Bindable]":
[Bindable]
private var _dp:ArrayCollection = null;
Et pour réaliser la liaison, on va mettre la variable entre crochets comme valeur de dataProvider:
<s:List width="100%" height="100%" dataProvider="{_dp}">
Création du model Pokemon.as
En ActionScript 3, on a la chance de pouvoir travailler avec des objets typés. Cela apporte de nombreux avantage, notamment en terme de performances, de lisibilité et de maintenance. Au lieu de récupérer une liste de Pokémon dans des objets non-typés (=type Object), on va créer notre model, qui va contenir les informations de la base de données.
Pour cela, on va créer une classe ActionScript nommée Pokemon qui va contenir plusieurs propriétés. Pour ne pas avoir tout en vrac, on va prendre de bonnes habitudes et créer un package "model". Dans le "Package Explorer", faîtes un clic droit sur "src" puis New > Package et nommez le "model".
Ensuite, faites un clic droit sur le package model puis New > ActionScript Class:
Donnez comme "Name", "Pokemon" puis Finish. Un fichier Pokemon.as a été créé. En ActionScript, comme en Java, on a 1 classe = 1 fichier. Ajoutez donc les propriétés suivantes à votre classe, qui correspondent aux types et aux noms de colonnes dans la base SQLite:
package model{
public class Pokemon{
public var id:String = null;
public var nom:String = null;
public var type:String = null;
public var evolue:int = -1;
public function Pokemon(){
}
}
}
Effectuer une requête SELECT sur la base
Dans notre méthode onCComplete, on va ajouter un appel vers une nouvelle méthode que l'on va nommer "getAll()". Au passage, on va voir une petite nouveauté de Flash Builder 4.5. Rendez-vous donc dans le corps de onCComplete, et après la récupération de la connexion, tapez "getAll()".
Flash Builder va vous indiquer que vous faîtes appel à une méthode inconnue, car effectivement, vous ne l'avez pas définie. Cliquez sur "getAll" puis lancez le raccourci Quick Assist: Ctrl+1 ou Cmd+1 sous Mac. Une aide rapide va vous proposer plusieurs options (bon, dans ce cas, une seule option):
Choisissez donc l'option "Create method 'getAll()'" et Flash Builder va vous faire directement la déclaration de la méthode juste en dessous. A la place de "// TODO Auto Generated method stub", on va mettre notre requête SELECT.
Pour apprendre comment effectuer une requête SELECT, je vous conseille de lire cet article:
AIR SQLite – Récupérer les données d'une base SQLite (SELECT)
En même temps, on va récupérer directement des objets typés Pokemon depuis la base de données comme expliqué dans cet article:
AIR SQLite – Typer les données renvoyées par un SELECT avec itemClass
Voici ce que cela donne dans le code:
private function getAll():void{
var sqlStatement:SQLStatement = new SQLStatement;
sqlStatement.sqlConnection = _sqlConnection;
try {
sqlStatement.text = "SELECT id,nom,type,evolue FROM pokemon order by nom";
sqlStatement.itemClass = Pokemon;
sqlStatement.execute();
var sqlResult:SQLResult = sqlStatement.getResult();
if (sqlResult && sqlResult.data) {
_dp = new ArrayCollection(sqlResult.data);
}
} catch (error:Error) {
trace("getAll::Erreur lors de la récupération");
}
}
On a créé notre requête SQL (SQLStatement), on lui a donné la référence vers notre SQLConnection puis assigné le texte de la requête. Pour avoir en retour des objets typés, on lui donne comme "itemClass", une référence vers notre classe Pokemon puis on l'exécute. On récupère le tableau de résultat et le donne à manger à "_dp" qui rappelez vous, est lié à notre liste.
Lancez l'application comme vous avez appris à le faire dans la partie 4 du tutorial et vous obtenez:
… Hum, ce n'est pas vraiment ce que l'on voulait, non? En fait, comme on l'a vu, on récupère un objet complexe de type Pokemon. Celui-ci contient plusieurs propriétés (id, nom, type, evolue) et de base, Flex ne va pas faire le choix de quelle propriété afficher dans la liste. En fait, si, il va quand même essayer de récupérer une propriété nommée "label" sur votre objet par défaut mais dans notre cas, pas de propriété "label".
On va donc indiquer à la liste que le label se trouve sur le champ "nom" avec la propriété "labelField":
<s:List width="100%" height="100%" dataProvider="{_dp}" labelField="nom">
Et voilà le résultat:
Et voilà, vous avez votre liste de pokémons! Vous pouvez apprécier le défilement fluide dans le simulateur.
Certaines étapes ont pu vous paraître un peu longue voire inutiles comme la création du Model Pokemon mais vous allez voir plus loin que ces "bonnes pratiques" vont vous faire gagner du temps par la suite.
Dans la prochaine partie, on va voir comment ajouter une zone de recherche pour filtrer la liste des pokémons.
Télécharger les sources
Vous pouvez télécharger le projet au format FXP tel qu'il est à la fin de cette partie:
Télécharger le projet au format FXP
Code complet de la vue
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView"
creationComplete="onCComplete(event)">
<fx:Script>
<![CDATA[
import model.Pokemon;
import mx.collections.ArrayCollection;
import mx.core.FlexGlobals;
import mx.events.FlexEvent;
private var _sqlConnection:SQLConnection = null;
[Bindable]
private var _dp:ArrayCollection = null;
protected function onCComplete(event:FlexEvent):void{
_sqlConnection = FlexGlobals.topLevelApplication.sqlConnection;
getAll();
}
private function getAll():void
{
var sqlStatement:SQLStatement = new SQLStatement;
sqlStatement.sqlConnection = _sqlConnection;
try {
sqlStatement.text = "SELECT id,nom,type,evolue FROM pokemon order by nom";
sqlStatement.itemClass = Pokemon;
sqlStatement.execute();
var sqlResult:SQLResult = sqlStatement.getResult();
if (sqlResult && sqlResult.data) {
_dp = new ArrayCollection(sqlResult.data);
}
} catch (error:Error) {
trace("getAll::Erreur lors de la récupération");
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:List width="100%" height="100%" dataProvider="{_dp}" labelField="nom">
</s:List>
</s:View>
Articles similaires
- AIR Mobile – Application Pokémon (6) – Filtrer la liste des pokémons avec un champ de recherche
- AIR Mobile – Application Pokémon (24) – Utiliser la persistance pour conserver des données
- AIR Mobile – Application Pokémon (17) – Afficher les évolutions du Pokémon (SQLite + navigation)
- AIR Mobile – Application Pokémon (32) – Utilisation de requêtes SQL paramétrées
- AIR SQLite – Récupérer les données d'une base SQLite (SELECT)











11 juillet 2011
Petite précision rapide pour les lecteurs novice en Flex et qui, à propos de la phrase suivante :
"qui est un tableau de données (mais en mieux).", pourraient se demander en quoi c'est mieux.
La différence entre Array et ArrayCollection est que ArrayCollection diffuse des événements lorsque la liste des éléments change (ajout, suppression, édition, …). Ces événements sont écoutés par les composants de type ListBase (List, DataGrid, Tree, …). Ainsi lorsqu'une source de données de type ArrayCollection est définie en tant que dataProvider d'un composant de type ListBase, le composant est automatiquement rafraichi lorsque la source de données change. Ce qui n'est pas le cas si la source est de type Array.
A noter aussi, et ça c'est moins connu : le type ArrayList, apparu dans Flex 4, qui est une version allégée de ArrayCollection. Il diffuse lui aussi des événements lorsque les données changent mais ne dispose pas par contre des fonctions de filtres et de tris. (filterFunction, sort). Pratique dans quelques cas donc
29 novembre 2011
Bonjour
Personnellement la liste reste irrémédiablement vide.
J'ai même essayé en copiant collant l'intégralité des exemples.
Si je clic droit et lance débuguer j'ai en message d'erreur
SQLError: 'Error #3125: Unable to open the database file.', details:'Connection closed.', operation:'open', detailID:'1001'
Je bloque un peu, j'ai vérifier le fichier sqlite est libre en lecture et écriture.
Merci de m'apporter votre aide.
29 novembre 2011
Salut,
Tu as essayé avec le FXP?
Fabien
30 novembre 2011
Bonjour
En relisant le tutos du début j'ai compris, j'avais oublié de copier les dossier dans bin-debug.
Merci