Bygg en kontaktprogram med jQuery Mobile og Android SDK - Del 4

I del 3 fortsatte vi denne serien ved å forklare hvordan du legger til en helt ny kontakt. Vi diskuterte også hvordan du bruker Android Java API for å få tilgang til og manipulere kontakter i en Android-enhet. Denne opplæringen er den endelige avgiften i serien, og i det vil vi forklare hvordan du sletter og lagrer en kontakt ved hjelp av Android Java API. Vi vil også beskrive utviklingsmiljøet for søknaden, diskutere konfigurasjonsfiler for prosjektet, og gi individuelle skritt for import av prosjektet til Eclipse IDE.


Skriv operasjoner for kontakter

Vi vil nå se på skriveoperasjoner om en kontakt. De er slett operasjon og lagre drift.

Slette en kontakt

Følgende metode i ContactUtility Klassen er ansvarlig for å slette en kontakt.

 offentlig statisk tomt sletteKontakt (String id, ContentResolver contentResolver, String accountType) HashMap kontakter = getUsersFromAccount (accountType, contentResolver); String existingContactId = contacts.get (id); hvis (existingContactId == null) // Kontakten tilhører ikke kontoen tilbake;  deleteContactInternal (id, contentResolver); 

Som nevnt tidligere tillater vi ikke å slette eller endre en kontakt i denne opplæringsprogrammet, med mindre det er opprettet av selve applikasjonen. (Dette er rett og slett for å unngå utilsiktet skade på en kontakt i en ekte enhet, gitt at dette bare er en opplæringsapplikasjon.) For å oppdage om en kontakt er opprettet av dette programmet, er det tilstrekkelig å kontrollere om kontakt tilhører konto med den spesifikke kontotypen for dette programmet. De deleteContact () metode ovenfor først utfører en metode som heter getUsersFromAccount () som returnerer en liste over alle kontakt-ID-er for en gitt kontotype. Hvis kontakt-ID-en som ble bedt om å slette, er i den listen, så deleteContactInternal () Metoden kalles for å faktisk slette kontakten. Ellers, deleteContact () Metoden returnerer uten å slette kontakten.

De ContactUtility.getUsersFromAccount () Metoden er oppført nedenfor. Den bruker tabellen, hvor klausul og kolonneavn i spørringen "Kontakter knyttet til en konto" ovenfor.

 importer java.util.HashMap ;? privat statisk HashMap GetUsersFromAccount (String accountType, ContentResolver contentResolver) Markørmarkør = contentResolver.query (ContactsContract.RawContacts.CONTENT_URI, null, ContactsContract.RawContacts.ACCOUNT_TYPE + "=?", ny String [] accountType, null); HashMap map = ny HashMap(); hvis (cursor.getCount ()> 0) mens (cursor.moveToNext ()) String contactId = cursor.getString (cursor.getColumnIndex (ContactsContract.RawContacts.CONTACT_ID)); map.put (kontaktId, kontaktId);  returkort; 

De ContactUtility.deleteContactInternal () Metoden er oppført nedenfor.

 importer android.net.Uri ;? privat statisk tomt slettContactInternal (String id, ContentResolver contentResolver) Markørmarkør = contentResolver.query (ContactsContract.Contacts.CONTENT_URI, null, ContactsContract.Contacts._ID + "=?", ny String [] id, null); String oppslag = null; hvis (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, oppslag); contentResolver.delete (uri, null, null); 

Slette en kontakt fra databasen består av disse trinnene.

  • Først spør databasen for å få kontaktoppføringen ved hjelp av ContactsContract.Contacts.CONTENT_URI som URI-basert representasjon av bordet.
  • Ved hjelp av ContactsContract.Contacts.LOOKUP_KEY som kolonnebeskrivelsen, få "oppslagstasten" for kontakten. Dette er en unik identifikator som skal brukes til å slette kontakten.
  • Konstruer a android.net.Uri objekt som konstruerer en URI-basert representasjon av kontaktens unike identifikator.
  • Anrop ContentResolver.delete () metode med Uri representasjon av kontakten for å slette den.

Lagre en kontakt

Lagring av en kontakt skjer i to scenarier. Kontakten kan være en eksisterende i databasen, eller det kan være en helt ny kontakt for hvilken tilknyttede poster må settes inn fra bunnen av.

For å lagre en eksisterende kontakt, kan man bruke forskjellige strategier. Eksempelvis kan eksisterende poster oppdateres basert på rad-ID for disse postene. I denne opplæringsprogrammet, for enkelhet, bestemte vi oss for å lagre en eksisterende kontakt ved først å slette den og deretter sette tilbake som en helt ny kontakt. Dette er en enkel tilnærming fordi den benytter metodene som allerede er skrevet for å slette en eksisterende kontakt og lagre en helt ny kontakt. Tilleggskode med 'oppdatering' operasjoner ikke nødvendig.

De ContactUtility.saveOrUpdateContact () Metoden er oppført nedenfor. Den brukes til både nye og eksisterende kontakter.

 offentlig statisk tomrom saveOrUpdateContact (Kontakt kontakt, ContentResolver contentResolver, String accountName, String accountType) if (kontakt == null || accountName == null || accountType == null) return;  String id = contact.getContactId (); hvis (! "" er lik (erstattNull (id))) // Dette er eksisterende kontakt for å oppdatere HashMap kontakter = getUsersFromAccount (accountType, contentResolver); String existingContactId = contacts.get (id); hvis (existingContactId == null) // Dette er knyttet til en annen konto - kan ikke behandle retur;  deleteContactInternal (id, contentResolver);  saveContact (kontakt, contentResolver, accountName, accountType); 
  • Det finnes ulike hygienekontroller, for å unngå null eller trivielle objekter. De replaceNull () metode, oppført nedenfor, konverterer en null streng til en tom streng og er en del av de sunnhetskontrollene.
  • Hvis id ikke er en tom streng, må den svare til en eksisterende kontakt i databasen. I så fall kontrollerer vi om det tilhører kontoen som er knyttet til dette programmet. (De getUsersFromAccount () Metoden har blitt vurdert ovenfor.) Hvis det ikke gjør det, må kontakten ikke endres, og metoden returnerer uten noen endring på kontoen.
  • Hvis kontakten tilhører kontoen som er tilknyttet dette programmet, slettes den.
  • Endelig, saveContact () Metoden kalles for å lagre kontakten.
 offentlig statisk String erstatteNull (String in) hvis (i == null) return "";  ellers return in; 

De ContactUtility.saveContact () Metoden er oppført nedenfor. Det definerer en liste over android.content.ContentProviderOperation forekomster for å sette inn individuelle poster og deretter samtaler ContentResolver.applyBatch () å utføre alle disse operasjonene samtidig.

  • Den første operasjonen forbinder den nyopprettede kontaktoppføringen med kontonavnet og kontotypen for dette programmet. Husk at kontonavnet ble spesifisert av brukeren når kontoen først ble opprettet og kontotype er konstanten com.jquerymobile.demo.contact.
  • Metoden ContentProviderOperation.newInsert () returnerer en forekomst av android.content.ContentProviderOperation.Builder klassen, som vanligvis brukes til å definere parameterverdier for ContentProviderOperation gjenstand. (Se følgende referanser for ContentProviderOperation og Bygger.) The Builder.withValue () operasjon returnerer samme forekomst av Bygger slik at vi kan rekursivt passere kolonneverdier for den innførte posten.
  • De withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) klausul tillater kobling av hver innsatsrekord med den første innsatsrekorden der "rot" kontaktrekordet er satt inn.
  • Etter den første innspillingsrekordet er ytterligere innsatte poster definert for for- og etternavn, notat, adresser, organisasjoner, e-post, chat-meldinger og telefoner i kontakten.
  • Endelig, ContentResolver.applyBatch () kalles for å utføre batchinnsatsoperasjoner mot databasen.
 importere android.content.ContentProviderOperation ;? privat statisk tomt lagreKontakt (Kontakt kontakt, ContentResolver contentResolver, String accountName, String accountType) ArrayListoperasjoner = ny ArrayList(); // Ny kontaktoppføring med kontoinformasjon operations.add (ContentProviderOperation.newInsert (ContactsContract.RawContacts.CONTENT_URI) .withValue (ContactsContract.RawContacts.ACCOUNT_TYPE, accountType) .withValue (ContactsContract.RawContacts.ACCOUNT_NAME, accountName) .build ()); // For- og etternavn operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.StructuredName .GIVEN_NAME, contact.getFirstName ()) .withValue (ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, contact.getLastName ()) .build ()); // Merk hvis (contact.getNote ()! = null) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds. Note.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Note.NOTE, contact.getNote (). GetText ()) .build ());  // Adresser Samling
adresser = contact.getAddresses (); hvis (adresser! = null) for (adresse adresse: adresser) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, KontakterContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.TYPE, address.getType ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.STREET, address.getStreet ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal .CITY, address.getCity ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.REGION, address.getState ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.POBOX, address.getPoBox ()) .withValue (ContactsContract.CommonDataKinds. StructuredPostal.POSTCODE, address.getZip ()) .withValue (ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, address.getCountry ()) .build ()); // Organisasjoner Samling organisasjoner = contact.getOrganizations (); hvis (organisasjoner! = null) for (Organisasjonsorganisasjon: organisasjoner) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, KontakterContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Organization.TYPE, organization.getType ()) .withValue (ContactsContract.CommonDataKinds.Organization.DATA, organization.getName ()) .withValue (ContactsContract.CommonDataKinds.Organization .TITLE, organization.getTitle ()) .build ()); // Emails Samling e-postadresser = contact.getEmails (); hvis (e-post! = null) for (e-postadresse: e-post) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, KontakterContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Email.TYPE, email.getType ()) .withValue (ContactsContract.CommonDataKinds.Email.DATA, email.getValue ()) .build ()); // IM Samling ims = contact.getIms (); hvis (ims! = null) for (Im im: ims) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, KontakterContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Im.PROTOCOL, im.getProtocol ()) .withValue (ContactsContract.CommonDataKinds.Im.DATA, im.getValue ()) .build ()); // Telefoner Samling telefoner = contact.getPhones (); hvis (telefoner = null) for (telefon telefon: telefoner) operations.add (ContentProviderOperation.newInsert (ContactsContract.Data.CONTENT_URI) .withValueBackReference (ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue (ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue (ContactsContract.CommonDataKinds.Phone.TYPE, phone.getType ()) .withValue (ContactsContract.CommonDataKinds.Phone.NUMBER, phone.getNo ()) .build ()); prøv contentResolver.applyBatch (ContactsContract.AUTHORITY, drift); fangst (unntak e)

Prosjektkonfigurasjon og støttefiler

Etter å ha vurdert koden, la oss nå se på konfigurasjon og andre støttefiler for prosjektet.

AndroidManifest.xml

  Pakken = "com.jquerymobile.demo.contact" android: versionCode = "1" android: versionName = "1.0"> /> />  />  />  <service android: name =".Authentication.AuthenticationService" android: eksportert = "true">     service> ".ContactsActivity" android: configChanges = "orientation | keyboardHidden" android: label = "@ streng / app_name">       
  • Pakkenavnet for søknaden vår er com.jquerymobile.demo.contact, som er spesifisert på toppnivå manifest element. Erklæringene .authentication.AuthenticationService og .ContactsActivity er i forhold til pakkenavnet.
  • Vi lister typene tillatelser som kreves av programmet via bruker-tillatelse elementer.
  • Vi hadde diskutert service element i 'Opprett konto', del 2 i denne opplæringen.

strings.xml

   Kontakt 

De strings.xml lagrer konstante strenger som brukes i søknaden. Den eneste konstanten vi bruker er app_name element som er navnet på søknaden. Verdien av den konstanten, "Kontakter", vises på forskjellige steder i Android-enheten, som vist i figuren nedenfor: Programmer-startskjermbildet (venstre), startskjermbildet (midten) og administrer programskjermbildet (høyre).

Figur 17. Programnavn.

Program Launch Icon

Lanseringsikonene for programmet er basert på Android GUI-elementene i http://www.matcheck.cz/androidguipsd/. Per Retningslinjer for Android-ikonet er tre ikonfiler opprettet som beskrevet nedenfor.

Mappenavn Filnavn Pixel størrelse
res \ teikne-ldpi icon.png 36 x 36
res \ teikne-mdpi icon.png 48 x 48
res \ teikne-HDPI icon.png 72 x 72

Disse ikonene er vist i figuren under. Ikonet til venstre er 36x36 piksler, den i midten er 48x48 piksler og den til høyre er 72x72 piksler.

Figur 18. Start ikoner.

Native Android Application Development Environment

Vi vil nå diskutere hvordan du importerer den opprinnelige applikasjonen til Eclipse utviklingsmiljø. Prosjektfilene ble testet mot:

  • Android SDK-versjon 8.
  • Eclipse IDE versjon 3.5
  • Android Development Tools (ADT), som er et Eclipse-plugin, versjon 8.0.1.

Prosjektet har blitt testet med Android platform 2.2 API nivå 8.

Importerer prosjektet

Før du importerer prosjektet til Eclipse-miljøet, må du kontrollere at Eclipse ADT-plugin peker på riktig sted for Android SDK i ditt lokale system. For å sjekke dette, gå til Eclipse-menyen Vinduet -> Innstillinger -> Android. De SDK-plassering Vinduet må settes til plasseringen av Android SDK. Når du er satt opp riktig, bør du se noe som ligner på under

Figur 19. Eclipse preferanser.

Prosjektfilene leveres i en arkivfil som heter contacts.zip. For å importere prosjektet, gå til Eclipse-menyen Fil -> Importer og velg deretter fil importveiviseren Generelt -> Eksisterende prosjekter i arbeidsområdet (se nedenfor).

Figur 20. Prosjektimport.

På neste side av veiviseren velger du Velg arkivfil: og bla til hvor contacts.zip ligger i filsystemet ditt. De prosjekter vinduet vil automatisk bli fylt der hvor ContactsDemo prosjektet er allerede valgt. Dette er vist nedenfor. trykk Bli ferdig knappen for å fullføre importen.

Figur 21. Valg av prosjektfil.

Eclipse vil bygge applikasjonen automatisk etter import. Nå bør du se ContactsDemo-prosjektet i prosjektutforskeren, som vist nedenfor.

Figur 22. Prosjekt Explorer.

Dette prosjektet er bygget og testet for Android OS 2.2-plattformen. For å bekrefte dette, velg ContactsDemo prosjekt i prosjektutforsker og fra høyreklikkmeny velg Eiendommer. På venstre side liste over egenskaper, velg Android som eiendommen. De tilgjengelige byggemålene vises til høyre, som vist nedenfor. Du bør se at Android 2.2 er valgt.

Figur 23. Android Build Target.

Filoppføring

En liste over filer i prosjektet er gitt nedenfor.

Figur 24. Filoppføring.
  • De src mappen lagrer Java-koden. Det er to pakker:
    • De com.jquerymobile.demo.contact pakken inneholder Adresse, Ta kontakt med, ContactDisplay, ContactGroup, ContactsActivity, ContactUtility, e-post, Jeg er, Merk, Organisasjon og telefon klasser.
    • De com.jquerymobile.demo.contact.authentication pakken inneholder authentiseringstjenesten klasse.
  • De gen mappen inneholder forskjellige filer som automatisk genereres av Eclipse ADT.
  • De eiendeler mappen lagrer HTML-filer, bildefiler som brukes i disse HTML-filene og jQuery Mobile / jQuery-biblioteker. Vi bruker jQuery Mobile versjon 1.0 Alpha 3, som var den siste utgivelsen da opplæringen ble skrevet. (En Alpha 4-utgivelse ble nylig laget med ulike feilrettinger. Se kunngjøringen.)
  • De lib mappen lagrer Jackson JSON biblioteker.
  • De res mappen lagrer ulike ressurser som kreves av søknaden. Det er ikonbildene og konfigurasjonsfilene strings.xml og authenticator.xml.
  • default.properties er en systemgenerert fil som definerer API-versjonen for Android-applikasjonen.
  • De proguard.cfg filen opprettes automatisk av utviklingsmiljøet og brukes av ProGuard-verktøyet. Detaljer finner du i ProGuard Documentation.

konklusjoner

I denne opplæringen implementerte vi et Android-program der brukergrensesnittet er konstruert via HTML / JavaScript, og kjernens innfødte funksjonalitet er utviklet via Java. En fordel ved denne tilnærmingen er at webutviklere, som allerede har kjennskap til HTML og JavaScript, kan bruke sin kunnskap til å konstruere brukergrensesnittet uten å måtte lære Android-spesifikke APIer, UI-hendelseshåndteringsmodell og Java-programmeringsspråket. På den annen side kan utviklere med Java-kompetanse fokusere på å bygge den innfødte funksjonaliteten ved hjelp av Android Java API. På denne måten kan arbeidsinnsatsen deles mellom to eller flere utviklere basert på eksisterende ferdighetssett.

Et typisk design hensyn til en Android-applikasjon er at den visuelle aspekter og hendelseshåndteringsmodell av brukergrensesnittet må være konsekvent på tvers av ulike enheter der applikasjonen skal installeres. Disse enhetene kan ha forskjellige skjermdimensjoner og kjøre forskjellige sett med nettlesere med forskjellige nivåer av HTML-støtte. I den forbindelse er jQuery Mobile gunstig fordi den gir lett tilgjengelige brukergrensesnittkomponenter med en støttende hendelseshåndteringsmodell. Den har allerede blitt testet for konsistens på tvers av ulike enheter og nettlesere, noe som gjør utviklingen på tvers av plattformen lettere.

Til slutt, vær oppmerksom på at enkelte programmer ikke passer inn i modellen ovenfor. For eksempel:

  • Visse applikasjoner krever sofistikerte brukergrensesnitt, f.eks. komplekse animasjoner, som kanskje ikke er mulig å konstruere ved hjelp av HTML-sider.
  • Man kan bruke et nettbasert programramme, for eksempel PhoneGap, for å få tilgang til innfødte funksjoner via en forenklet JavaScript-API, hvis APIen er tilstrekkelig til å tilfredsstille forretningsbehovene. I dette tilfellet kan brukergrensesnitt fortsatt bygges med jQuery Mobile, men det kan ikke være nødvendig å utvikle Java-backend-kode.