Construire une application Contacts avec jQuery Mobile et le SDK Android - Partie 4

Dans la troisième partie, nous avons poursuivi cette série en expliquant comment ajouter un nouveau contact. Nous avons également expliqué comment utiliser l'API Java Android pour accéder aux contacts d'un périphérique Android et les manipuler. Ce didacticiel est le dernier volet de la série. Il explique comment supprimer et enregistrer un contact à l’aide de l’API Java Android. Nous allons également décrire l'environnement de développement de l'application, discuter des fichiers de configuration du projet et indiquer les étapes à suivre pour importer le projet dans l'EDI Eclipse..


Opérations d'écriture pour les contacts

Nous allons maintenant examiner les opérations d'écriture concernant un contact. Ce sont des opérations de suppression et de sauvegarde.

Supprimer un contact

La méthode suivante en ContactUtilité la classe est responsable de la suppression d'un contact.

 public static void deleteContact (Identificateur de chaîne, ContentResolver contentResolver, String accountType) HashMap contacts = getUsersFromAccount (accountType, contentResolver); String existingContactId = contacts.get (id); if (existingContactId == null) // Le contact n'appartient pas à compte return;  deleteContactInternal (id, contentResolver); 

Comme mentionné précédemment, nous ne permettons pas de supprimer ou de modifier un contact dans cette application de tutoriel, à moins qu'il ait été créé par l'application elle-même. (Ceci est simplement pour éviter d'endommager accidentellement un contact dans un périphérique réel, étant donné qu'il s'agit simplement d'une application tutoriale.) Pour détecter si un contact a été créé par cette application, il suffit de vérifier si le contact appartient au compte avec le type de compte spécifique pour cette application. le supprimer le contact() La méthode ci-dessus exécute d'abord une méthode nommée getUsersFromAccount () qui retourne une liste de tous les identifiants de contact pour un type de compte donné. Si le contact demandé pour la suppression se trouve dans cette liste, deleteContactInternal () La méthode est appelée pour réellement supprimer le contact. Autrement, supprimer le contact() méthode retourne sans supprimer le contact.

le ContactUtility.getUsersFromAccount () La méthode est listée ci-dessous. Il utilise la table, où les noms de clause et de colonne dans la requête "Contacts associés à un compte" ci-dessus.

 importer java.util.HashMap ;? HashMap statique privée getUsersFromAccount (String accountType, ContentResolver contentResolver) curseur du curseur = contentResolver.query (ContactsContract.RawContacts.CONTENT_URI, null, ContactsContract.RawContacts.ACCOUNT_TYPE + "=?", nouveau String [] accountType, null); HashMap map = new HashMap(); if (cursor.getCount ()> 0) while (cursor.moveToNext ()) String contactId = cursor.getString (cursor.getColumnIndex (ContactsContract.RawContacts.CONTACT_ID)); map.put (contactId, contactId);  carte de retour; 

le ContactUtility.deleteContactInternal () la méthode est énumérée ci-dessous.

 importer android.net.Uri ;? voic statique privé deleteContactInternal (ID de chaîne, ContentResolver contentResolver) Curseur curseur = contentResolver.query (ContactsContract.Contacts.CONTENT_URI, null, ContactsContract.Contacts._ID + "=?", nouveau String [] id, null); Recherche de chaîne = null; if (cursor.getCount ()> 0) while (cursor.moveToNext ())  lookup = cursor.getString (cursor.getColumnIndex (ContactsContract.Contacts.LOOKUP_KEY));   cursor.close (); Uri uri = Uri.withAppendedPath (ContactsContract.Contacts.CONTENT_LOOKUP_URI, recherche); contentResolver.delete (uri, null, null); 

Supprimer un contact de la base de données comprend ces étapes.

  • Commencez par interroger la base de données pour obtenir l'enregistrement du contact à l'aide de ContactsContract.Contacts.CONTENT_URI comme représentation de la table basée sur l'URI.
  • En utilisant ContactsContractes.Contacts.LOOKUP_KEY en tant que descripteur de colonne, obtenez la "clé de recherche" du contact. C'est un identifiant unique à utiliser pour supprimer le contact..
  • Construire un android.net.Uri objet qui construit une représentation basée sur l'URI de l'identifiant unique du contact.
  • Appel ContentResolver.delete () méthode avec le Uri représentation du contact pour le supprimer.

Enregistrement d'un contact

L'enregistrement d'un contact se produit dans deux scénarios. Le contact peut être un contact existant dans la base de données ou un nouveau contact pour lequel des enregistrements associés doivent être insérés à partir de zéro..

Pour enregistrer un contact existant, différentes stratégies peuvent être utilisées. Par exemple, les enregistrements existants peuvent être mis à jour en fonction de l'ID de ligne de ces enregistrements. Dans ce tutoriel, pour des raisons de simplicité, nous avons décidé de sauvegarder un contact existant en le supprimant d’abord, puis en le réinsérant en tant que nouveau contact. Cette approche est simple car elle utilise les méthodes déjà écrites pour supprimer un contact existant et enregistrer un tout nouveau contact. Code supplémentaire avec opérations de mise à jour non nécessaire.

le ContactUtility.saveOrUpdateContact () La méthode est listée ci-dessous. Il est utilisé pour les contacts nouveaux et existants.

 public static void saveOrUpdateContact (Contact, ContentResolver, contentResolver, String nomCompte, String typeCompte) if (contact == null || nomCompte == null || typeCompte == null) return;  String id = contact.getContactId (); if (! "". equals (replaceNull (id))) // Ceci est un contact existant pour mettre à jour HashMap. contacts = getUsersFromAccount (accountType, contentResolver); String existingContactId = contacts.get (id); if (existingContactId == null) // Ceci est associé à un autre compte - impossible de traiter le retour;  deleteContactInternal (id, contentResolver);  saveContact (contact, contentResolver, accountName, accountType); 
  • Il existe plusieurs contrôles de cohérence pour éviter les objets nuls ou triviaux. le replaceNull () La méthode, listée ci-dessous, convertit une chaîne null en une chaîne vide et fait partie de ces contrôles de cohérence..
  • Si l'id n'est pas une chaîne vide, elle doit correspondre à un contact existant dans la base de données. Dans ce cas, nous vérifions s'il appartient au compte associé à cette application. (Le getUsersFromAccount () méthode a été examinée ci-dessus.) Si ce n'est pas le cas, le contact ne doit pas être modifié et la méthode est renvoyée sans modification du compte..
  • Si le contact appartient au compte associé à cette application, il est supprimé..
  • finalement, saveContact () méthode est appelée pour enregistrer le contact.
 public static String replaceNull (String in) if (in == null) return "";  else retour dans; 

le ContactUtility.saveContact () La méthode est listée ci-dessous. Il définit une liste de android.content.ContentProviderOperation instances pour l'insertion d'enregistrements individuels, puis les appels ContentResolver.applyBatch () d'effectuer toutes ces opérations à la fois.

  • La première opération associe l'enregistrement de contact nouvellement créé au nom et au type de compte de cette application. Rappelez-vous que le nom du compte a été spécifié par l'utilisateur lors de la création du compte et que le type de compte est la constante. com.jquerymobile.demo.contact.
  • La méthode ContentProviderOperation.newInsert () retourne une instance de android.content.ContentProviderOperation.Builder classe, qui est généralement utilisé pour définir des valeurs de paramètre pour ContentProviderOperation objet. (Voir les références suivantes pour ContentProviderOperation et Constructeur.) Le Builder.withValue () l'opération retourne la même instance du Constructeur nous permettant de transmettre récursivement les valeurs de colonne pour l'enregistrement inséré.
  • le withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) la clause permet de lier chaque enregistrement d'insertion avec le premier enregistrement d'insertion où l'enregistrement de contact 'racine' est inséré.
  • Après le premier enregistrement d'insertion, des enregistrements d'insertion supplémentaires sont définis pour le prénom et le nom, la note, les adresses, les organisations, les e-mails, les messages instantanés et les téléphones du contact..
  • finalement, ContentResolver.applyBatch () est appelé pour effectuer les opérations d'insertion par lots sur la base de données.
 importer android.content.ContentProviderOperation ;? saveContact statique privé privé (Contact, ContentResolver contentResolver, String accountName, String accountType) ArrayListoperations = new ArrayList(); // Nouvel enregistrement de contact avec informations de compte operations.add (ContentProviderOperation.newInsert (ContactsContract.RawContacts.CONTENT_URI) .withValue (ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) .withValue (ContactsContract.RawContacts.ACCOUNT_NAME, accountName); // prénom et nom la gestion de la sécurité .GIVEN_NAME, contact.getFirstName ()) .withValue (ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, contact.getLastName ()) .build ()); // Remarque if (contact.getNote ()! = null) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETy), Note.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Note.NOTE, contact.getNote (). GetText ()) .build ());  // adresses Collection
adresses = contact.getAddresses (); if (adresses! = null) pour (adresse_adresses: adresses) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, ContactsContracteur .CITY, address.getCity ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.REGION, address.getState ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.POBOX, address.getPoBox (contactsContract.personnel). StructuredPostal.POSTCODE, address.getZip ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, address.getCountry ()) .build ()); // Organisations Collection organisations = contact.getOrganizations (); if (organisations! = null) pour (Organisation organisationnelle: organisations) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MD. ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Organization.TYPE, organization.getType ()) .withValue (ContactsContract.CommonDataKinds.Organization.DATA, organisation.getName () .TITLE, organization.getTitle ()) .build ()); // Courriels Collection emails = contact.getEmails (); if (emails! = null) pour (Email email: emails) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Email.TYPE, email.getType ()) .withValue (ContactsContract.CommonDataKinds.Email.DATA, email.getValue ()); // MI Collection ims = contact.getIms (); if (ims! = null) pour (Im im: ims) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Im.PROTOCOL, im.getProtocol ()) .withValue (ContactsContract.CommonDataKinds.Im.Dget, im.getValue ()); // Téléphones Collection téléphones = contact.getPhones (); if (phones! = null) for (phone phone: phones) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data. ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Phone.TYPE, phone.getType ()) .withValue (ContactsContract.CommonDataKinds.Phone.NUMBER, phone.getNo ()); essayer contentResolver.applyBatch (ContactsContract.AUTHORITY, opérations); catch (exception e)

Configuration du projet et fichiers de support

Après avoir examiné le code, examinons maintenant la configuration et d’autres fichiers d’appui pour le projet..

AndroidManifest.xml

  package = "com.jquerymobile.demo.contact" android: versionCode = "1" android: versionName = "1.0"> /> />  />  />  <un service Android: nom =".authentication.AuthenticationService" android: exports = "true">     un service> ".ContactsActivity" android: configChanges = "orientation | keyboardHidden" android: label = "@ string / nom_app" ">       
  • Le nom du paquet pour notre application est com.jquerymobile.demo.contact, qui est spécifié dans le niveau supérieur manifeste élément. Les déclarations .authentication.AuthenticationService et .ContactsActivité sont relatifs au nom du paquet.
  • Nous listons les types d'autorisations requises par l'application via utilisations-permission éléments.
  • Nous avions discuté de la un service élément dans 'Créer un compte', partie 2 de ce tutoriel.

strings.xml

   Contacts 

le strings.xml stocke les chaînes constantes utilisées dans l'application. La seule constante que nous utilisons est la nom de l'application élément qui est le nom de l'application. La valeur de cette constante, "Contacts", est affichée à différents endroits du périphérique Android, comme illustré dans la figure ci-dessous: écran du lanceur d'applications (à gauche), écran d'accueil (au centre) et écran de gestion des applications (à droite).

Figure 17. Nom de l'application.

Icône de lancement d'application

Les icônes de lancement de l'application sont basées sur les éléments de l'interface graphique Android de http://www.matcheck.cz/androidguipsd/. Conformément aux directives de conception d’icône Android, trois fichiers d’icône ont été créés comme décrit ci-dessous..

Nom de dossier Nom de fichier Taille de pixel
res \ drawable-ldpi icon.png 36 x 36
res \ drawable-mdpi icon.png 48 x 48
res \ drawable-hdpi icon.png 72 x 72

Ces icônes sont illustrées dans la figure ci-dessous. L'icône à gauche est de 36x36 pixels, celle du milieu de 48x48 pixels et celle de droite de 72x72 pixels..

Figure 18. Icônes de lancement.

Environnement de développement d'applications Android natif

Nous allons maintenant discuter de la façon d'importer l'application native dans l'environnement de développement Eclipse. Les fichiers de projet ont été testés contre:

  • SDK Android révision 8.
  • Eclipse IDE version 3.5
  • Android Development Tools (ADT), un plugin Eclipse, version 8.0.1.

Le projet a été testé avec succès par rapport à la plate-forme Android 2.2 API de niveau 8.

Importer le projet

Avant d'importer le projet dans votre environnement Eclipse, assurez-vous que le plug-in Eclipse ADT pointe vers l'emplacement correct du SDK Android dans votre système local. Pour vérifier cela, dans le menu Eclipse, allez à Fenêtre -> Préférences -> Android. le SDK Emplacement La fenêtre doit être définie sur l'emplacement du SDK Android. Une fois configuré correctement, vous devriez voir quelque chose de similaire à ci-dessous

Figure 19. Préférences Eclipse.

Les fichiers de projet sont fournis dans un fichier d’archive nommé contacts.zip. Pour importer le projet, dans le menu Eclipse, allez à Fichier -> Importer puis dans l'assistant d'importation de fichier, sélectionnez Général -> Projets existants dans l'espace de travail (voir ci-dessous).

Figure 20. Importation de projet.

Sur la page suivante de l’assistant, choisissez Sélectionnez le fichier archive: et naviguez où contacts.zip se trouve dans votre système de fichiers. le Projets fenêtre sera automatiquement rempli où la ContactsDemo le projet est déjà sélectionné. Ceci est montré ci-dessous. appuyez sur la terminer bouton pour terminer l'importation.

Figure 21. Sélection du fichier de projet.

Eclipse construira l'application automatiquement après l'importation. Maintenant, vous devriez voir le projet ContactsDemo dans l'explorateur de projet, comme indiqué ci-dessous.

Figure 22. Explorateur de projet.

Ce projet a été construit et testé pour la plate-forme Android OS 2.2. Pour le vérifier, sélectionnez le ContactsDemo projet dans l'explorateur de projet et dans le menu contextuel, choisissez Propriétés. Sur la liste de gauche des propriétés, sélectionnez Android comme la propriété. Les cibles de construction disponibles sont affichées à droite, comme indiqué ci-dessous. Vous devriez voir que Android 2.2 a été sélectionné.

Figure 23. Cible de construction Android.

Liste de fichiers

Une liste des fichiers du projet est donnée ci-dessous.

Figure 24. Liste de fichiers.
  • le src dossier stocke le code Java. Il y a deux forfaits:
    • le com.jquerymobile.demo.contact le paquet contient Adresse, Contact, ContactDisplay, ContactGroupe, ContactsActivité, ContactUtilité, Email, Je suis, Remarque, Organisation et Téléphone Des classes.
    • le com.jquerymobile.demo.contact.authentication le paquet contient le AuthenticationService classe.
  • le gen dossier contient divers fichiers générés automatiquement par Eclipse ADT.
  • le les atouts dossier stocke les fichiers HTML, les fichiers image utilisés dans ces fichiers HTML et les bibliothèques jQuery Mobile / jQuery. Nous utilisons la version 1.0 Alpha 3 de jQuery Mobile, qui était la dernière version au moment de la rédaction du didacticiel. (Une version Alpha 4 a récemment été publiée avec diverses corrections de bugs. Voir l'annonce.)
  • le lib dossier stocke les bibliothèques Jackson JSON.
  • le res dossier stocke diverses ressources nécessaires à l'application. Ce sont les images d'icônes et les fichiers de configuration strings.xml et authenticator.xml.
  • default.properties est un fichier généré par le système qui définit la version de l'API pour l'application Android.
  • le proguard.cfg Le fichier est automatiquement créé par l'environnement de développement et utilisé par l'outil ProGuard. Des détails peuvent être trouvés dans la documentation ProGuard.

Conclusions

Dans ce tutoriel, nous avons implémenté une application Android dans laquelle l'interface utilisateur est construite via HTML / JavaScript et la fonctionnalité native native est développée via Java. Un avantage de cette approche est le fait que les développeurs Web, déjà familiarisés avec HTML et JavaScript, peuvent utiliser leurs connaissances pour construire l'interface utilisateur sans avoir à apprendre les API spécifiques à Android, le modèle de gestion des événements d'interface utilisateur et le langage de programmation Java. D'autre part, les développeurs ayant une expertise Java peuvent se concentrer sur la création de la fonctionnalité native à l'aide de l'API Java Android. De cette façon, le travail peut être divisé entre deux ou plusieurs développeurs en fonction des compétences existantes.

Un aspect typique de la conception d’une application Android est que les aspects visuels et le modèle de gestion des événements de l’interface utilisateur doivent être cohérents sur les différents périphériques sur lesquels l’application sera installée. Ces périphériques peuvent avoir différentes dimensions d’écran et exécuter divers ensembles de navigateurs Web avec différents niveaux de prise en charge HTML. À cet égard, jQuery Mobile est avantageux car il fournit des composants d'interface utilisateur facilement disponibles avec un modèle de gestion des événements compatible. Sa cohérence a déjà été testée sur différents appareils et navigateurs, ce qui facilite le développement multi-plateformes..

Enfin, veuillez noter que certaines applications ne rentrent pas dans le modèle ci-dessus. Par exemple:

  • Certaines applications nécessitent des composants d'interface utilisateur sophistiqués, par exemple animations complexes, qu'il est parfois impossible de construire avec des pages HTML.
  • Vous pouvez utiliser une infrastructure d'application Web, telle que PhoneGap, pour accéder à des fonctionnalités natives via une API JavaScript simplifiée, si cette dernière est suffisante pour répondre aux exigences de l'entreprise. Dans ce cas, l'interface utilisateur peut toujours être construite avec jQuery Mobile. Toutefois, il peut ne pas être nécessaire de développer du code back-end Java..