Gå til hovedindhold
Version2 it for professionelle
Forsiden

Hovedmenu

  • It-nyheder
  • Blogs
  • It-job
  • It-firmaer
  • Emner
  • Opret bruger
  • Log ind
Emner Java, Android

Android-skolen del 5: Byg tre små robotter sammen til én stor

Sidste ombæring af Android-skolen får koden fra de tidligere afsnit til at spille i én og samme applikation. Kodeordene er faneblade og separate layout-filer til brugergrænsefladen.

Af Mikkel Meister Onsdag, 23. december 2009 - 14:42

Velkommen til femte og sidste lektion i Version2's Android-skole.

Denne gang går vi et spadestik dybere i den måde, androidens grafiske brugergrænseflade bygges op på.

Tanken er at vise, hvordan flere selvstændige applikationer ? eller activities - kan samles i én og samme brugergrænseflade, og det gør vi ganske enkelt ved at hugge koden fra afsnit 2, 3 og 4 af Android-skolen og lægge al funktionaliteten ind i én og samme applikation, adskilt grafisk af tre faneblade.

Denne gang er det altså mere 'skelettet' uden om koden, end selve koden, der fokuseres på.

Foreløbig har vi set på forskellige typer af views og layouts. For eksempel brugte vi et ListView til at vise kontakterne i telefonbogen i Android-skolen del 2, mens Android-skolen del 3 bød på et MapView til vores Google Maps/GPS-applikation.

Under første faneblad placeres telefonbogen fra afsnit 2. Andet faneblad indeholder Google Maps/GPS-applikationen fra afsnit 3, og tredje faneblad viser applikationen fra afnit 4, der demonstrerer trådning af den grafiske brugergrænseflade.

Gæsteunderviser er denne gang atter Klaus Kartou, der er en af hovedudviklerne bag den danske koncertapplikation til Android-platformen, Gigbox.

»Tabs er generelt en god måde at samle forskellig funktionalitet i samme vindue. Det gør det nemt for brugeren at overskue flere activities og skifte imellem dem,« siger Klaus Kartou.

1) Lidt teori om GUI-design med Android

Filen R.java (ligger under projektundermappen 'gen') forbinder vores Java-kildekode med det grafiske layout af brugergrænsefladen, der specificeres i XML-filen main.xml. R.java autogenereres ud fra layoutet i main.xml, og derfor ændrer vi aldrig direkte i den.

I de foregående afsnit har vi holdt os til at definere layoutet i én og samme fil, main.xml, men da vi denne gang skal håndtere flere forskellige slags views i samme brugergrænseflade, skal der flere XML-filer på banen.

Idéen er derfor at oprette nye XML-filer til hvert af de tre faneblade i applikationen. Vi ender derfor med filerne:

  • main.xml: Indeholder det overordnede faneblad-layout.
  • phonebook.xml: Indeholder layoutet af telefonbog-applikationen
  • mapview.xml: Indeholder layoutet af Google Maps/GPS-applikationen
  • progressbar.xml: Indeholder layoutet af trådning-applikationen, der viser en progressbar.

De største ændringer sker i main.xml, idet de andre XML-filer blot indeholder layoutet som angivet i de respektive afsnit af Android-skolen.

## 2) Opret projekt og klasse-filer Start Eclipse.

Opret et nyt Android-projekt, ganske som du plejer. Navngiv applikationen som vist nedenfor, eller efter eget valg.

Bemærk, at du skal vælge Google API'et i version 1.6, da faneblad nummer to som nævnt indeholder Google Maps-applikationen.

Du har nu oprettet projektet med selve hovedklassen AndroidSkolenDel5, som er ansvarlig for at oprette faneblade og lægge applikationerne fra afsnit 2, 3 og 4 ind under dem.

Indtil videre indeholder AndroidSkolenDel5 blot en autogenereret onCreate()-metode, og vi lader den stå sådan et øjeblik.

Nu skal du oprette de klasser, der indeholder koden til de tre foregående applikationer. Opret filerne

  • MyPhoneBook.java
  • MyMap.java
  • MyProgressBar.java

og sørg for, at de ligger placeret samme sted som AndroidSkolenDel5.java (underbiblioteket 'src').

Herefter tager du 'indmaden' fra klasserne i de foregående afsnit af Android-skoeln og kopierer koden ind i de nyoprettede filer efter fremgangsmåden:

  • AndroidSkolenDel2.java -> MyPhoneBook.java
  • AndroidSkolenDel3.java -> MyMap.java
  • AndroidSkolenDel4.java -> MyProgressBar.java

Husk at sætte de nye klasser til arve fra de samme klasser og interfaces, som var tilfældet i de 'gamle' klasser.

  • MyPhoneBook.java: extends ListActivity
  • MyMap.java: extends MapActivity implements LocationListener
  • MyProgressBar.java: extends Activity

Dermed ser eksempelvis MyMap.java nu sådan ud (forkortet i bunden):

01 **public class **MyMap **extends **MapActivity **implements **LocationListener { 02   **private **Location location; 03   **private **MapView mapView; 04   **private **MapController mc; 05   **private **LocationManager locationManager; 06  07   **public ****void **onCreate(Bundle savedInstanceState) { 08     **super**.onCreate(savedInstanceState); 09     setContentView(R.layout.main); 10  11     mapView = (MapView) findViewById(R.id.mapview1); 12     mapView.setBuiltInZoomControls(**true**); 13     mc = mapView.getController(); 14   } 15  16   **protected ****void **onResume() { 17     List providers; 18     **super**.onResume(); 19         ...

3) Definer layouts i XML-filer

Som nævnt tidligere skal du oprette nye XML-filer til hver af de tre activities, der skal vises i hver deres faneblad.

  • main.xml: Indeholder det overordnede faneblad-layout.
  • phonebook.xml: Indeholder layoutet af telefonbog-applikationen
  • mapview.xml: Indeholder layoutet af Google Maps/GPS-applikationen
  • progressbar.xml: Indeholder layoutet af trådning-applikationen, der viser en progressbar.

Main.xml er oprettet til os på forhånd. Den lader vi ligge et øjeblik.

Vi går videre med at kopiere layoutet fra filen main.xml i projekterne Android-skolen del 2, 3 og 4 ind i tre nye XML-filer.

  • phonebook.xml
  • mapview.xml
  • progressbar.xml

Filerne oprettes i Eclipse ved at taste ctrl+N og vælge Android XML File under punktet Android.

XML-filerne ser nu ud som følger:

  • phonebook.xml:

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   android:orientation="vertical" android:layout_width="fill_parent" 04   android:layout_height="fill_parent"> 05   "@id/android:list" android:layout_width="fill_parent" 06     android:layout_height="fill_parent" android:layout_weight="1" /> 07   "@+id/name" android:textSize="18px" 08     android:textStyle="bold" android:layout_width="fill_parent" 09     android:layout_height="wrap_content" /> 10   "@+id/phone_number" android:layout_width="fill_parent" 11     android:layout_height="wrap_content" /> 12 

Læg her mærke til, at vi har tilføjet et ListView-tag til phonebook.xml i linje 5-6, da vi ellers får en fejl på runtime.

  • mapview.xml:

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   android:orientation="vertical" android:layout_width="fill_parent" 04   android:layout_height="fill_parent"> 05  06    07     android:id="@+id/mapview1" android:layout_width="fill_parent" 08     android:layout_height="fill_parent" android:enabled="true" 09     android:clickable="true" android:apiKey="0Svjiran6ZYsb5ENaZ-B-_ZNl5p65sLmX87VuSQ" /> 10 

  • progressbar.xml:

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   android:orientation="vertical" android:layout_width="fill_parent" 04   android:layout_height="fill_parent"> 05   "@+id/my_button" android:layout_width="100px" 06     android:layout_height="wrap_content" android:text="foo" /> 07   "@+id/progress_bar" 08     android:layout_width="fill_parent" android:layout_height="wrap_content" 09     style="?android:attr/progressBarStyleHorizontal" /> 10 

Nu har du oprettet XML-filerne og skal derefter blot bede Java-filerne om at hente layoutet derfra, i stedet for i main.xml.

Det gøres ganske enkelt ved at erstatte metodekaldet setContentView(R.layout.main) i linje to af onCreate()-metoden i de tre filer MyPhoneBook.java, MyMap.java og MyProgressBar.java med henholdsvis

  • MyPhoneBook.java: setContentView(R.layout.phonebook)
  • MyMap.java: setContentView(R.layout.mapview)
  • MyProgressBar.java: setContentView(R.layout.progressbar)

Bemærk, at du i MyPhoneBook.java også skal ændre i metodekaldet

cursorAdapter = new SimpleCursorAdapter(this, R.layout.main, c, columns, contacts);

nederst i onCreate()-metoden. Her skal andet argument, R.layout.main, også ændres til R.layout.phonebook.

4) Opret fanebladene Nu har du oprettet tre nye klasser, som definerer de activities, vi gerne vil afvikle i de tre faneblade i vores layout, og du har samtidig skabt tre nye XML-filer, der indeholder de respektive layouts til de tre activities.

Inden vi skriver kode i selve hovedklassen, AndroidSkolenDel5.java, lægger vi ud med at definere layoutet for klassens activity i main.xml.

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   android:id="@android:id/tabhost" android:layout_width="fill_parent" 04   android:layout_height="wrap_content" layout_weight="1"> 05   "vertical" 06     android:layout_width="fill_parent" android:layout_height="fill_parent"> 07     "@android:id/tabs" 08       android:layout_width="fill_parent" android:layout_height="wrap_content" /> 09     "@android:id/tabcontent" 10       android:layout_width="fill_parent" android:layout_height="fill_parent"> 11      12    13 

Vi har her defineret en TabHost, der indeholder hele layoutet for vores activity. En TabHost skal indeholde en TabWidget og et FrameLayout som underelementer, og vi sørger for at layoute dem ordenligt i et LinearLayout. Framelayoutet er der, vi opbevarer det indhold, der skal være i et faneblad.

Med layoutet på plads i main.xml retter vi nu opmærksomheden mod vores hovedklasse, AndroidSkolenDel5.java. Her skal du nu oprette fanebladene og fylde dem ud med indholdet af de tre activities.

Det gøres ved at oprette en såkaldt TabHost og fortælle den, hvad du gerne vil have puttet ind i de enkelte faneblade.

Begynd med at sætte AndroidSkolenDel5.java til at arve fra TabActivity i stedet for Activity.

Dernæst fylder vi onCreate()-metoden ud med kode som følger:

01 **public class **AndroidSkolenDel5 **extends **TabActivity { 02  03   **private **TabHost mTabHost; 04  05   **public ****void **onCreate(Bundle savedInstanceState) { 06     **super**.onCreate(savedInstanceState); 07     setContentView(R.layout.main); 08  09     mTabHost = getTabHost(); 10  11     Context ctx = getApplicationContext(); 12      13     Intent phoneBook = **new **Intent(ctx, MyPhoneBook.**class**); 14     Intent map = **new **Intent(ctx, MyMap.**class**); 15     Intent progressBar = **new **Intent(ctx, MyProgressBar.**class**); 16      17     mTabHost.addTab(mTabHost.newTabSpec("tab_test1").setIndicator("Fane 1") 18         .setContent(phoneBook)); 19     mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("Fane 2") 20         .setContent(map)); 21     mTabHost.addTab(mTabHost.newTabSpec("tab_test3").setIndicator("Fane 3") 22         .setContent(progressBar)); 23      24     mTabHost.setCurrentTab(0); 25   } 26 }

Vi tager den ét skridt ad gangen.

I linje 9 benytter vi metodekaldet getTabHost() til at hente en reference til den TabHost, vi har defineret i layoutet i main.xml.

I linje 11 henter vi den kontekst, vores applikation har lige nu, med kaldet getApplicationContext().

Det bruges som argument til de tre Intents, vi definerer i linje 13-15. Et Intent er en abstraktion over en handling, vi gerne vil udføre ? i dette tilfælde telefonbogen, kortapplikationen og trådapplikationen ? som vi efterfølgende giver med som argument til metodekaldene i linje 17-22, der tilføjer tre faneblade med indhold til vores TabHost.

»TabActivity benytter Intents til at specificere, hvilken activity der er knyttet til en given tab. Når brugeren klikker på en tab, startes den pågældende activity, og dens tilhørende vindue indsættes i TabActivitiens tab-contentview,« siger Klaus Kartou.

I linje 24 slutter vi af med at sætte det første faneblad som den aktuelle fane og dermed den første fane, brugeren ser, når applikationen startes op.

5) Sæt permissions og activities i manifestet Sidste punkt på listen, inden vi kan køre vores nye applikation, er at sætte de permissions, vi skal bruge, i AndroidManifest.xml.

Det drejer sig om de fem uses-permission-tags vist i linje 4-10 herunder:

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   **package**="dk.version2.as5" android:versionCode="1" android:versionName="1.0"> 04   "android.permission.ACCESS_FINE_LOCATION"> 05    06   "android.permission.ACCESS_COARSE_LOCATION"> 07    08   "android.permission.INTERNET"> 09   "android.permission.READ_CONTACTS"> 10   "android.permission.CALL_PHONE"> 11   "@drawable/icon" android:label="@string/app_name" 12     android:debuggable="true"> 13     "com.google.android.maps" /> 14     ".AndroidSkolenDel5" android:label="@string/app_name"> 15     ...

, der giver os lov til at bruge både GPS og triangulering og tilgå dataforbindelsen til Google Maps/GPS-applikationen, samt læse kontakterne fra telefonens adressebog og ringe dem op i telefonbog-applikationen.

Samtidig har vi defineret i linje 13, at vores applikation bruger Google Maps.

Som det ser ud lige nu, har vi kun defineret AndroidSkolenDel5.java som en activity i manifestet. For at kunne afvikle de tre foregående applikationer i fanebladene, skal vi også definere dem som activities i manifestet.

Det gøres ved at tilføje tre activities efter activity'en AndroidSkolenDel5:

1     ...   2      3     ".MyPhoneBook" android:label="@string/app_name"> 4      5     ".MyMap" android:label="@string/app_name"> 6      7     ".MyProgressBar" android:label="@string/app_name"> 8      9     ...

Dermed kommer det samlede manifest til at se således ud:

01 "1.0" encoding="utf-8"?> 02 "http://schemas.android.com/apk/res/android" 03   **package**="dk.version2.as5" android:versionCode="1" android:versionName="1.0"> 04   "android.permission.ACCESS_FINE_LOCATION"> 05    06   "android.permission.ACCESS_COARSE_LOCATION"> 07    08   "android.permission.INTERNET"> 09   "android.permission.READ_CONTACTS"> 10   "android.permission.CALL_PHONE"> 11   "@drawable/icon" android:label="@string/app_name" 12     android:debuggable="true"> 13     "com.google.android.maps" /> 14     ".AndroidSkolenDel5" android:label="@string/app_name"> 15        16         "android.intent.action.MAIN" /> 17         "android.intent.category.LAUNCHER" /> 18        19      20     ".MyPhoneBook" android:label="@string/app_name"> 21      22     ".MyMap" android:label="@string/app_name"> 23      24     ".MyProgressBar" android:label="@string/app_name"> 25      26    27   "4" /> 28 

Gem projektet og oversæt og kør det med ctrl+b efterfulgt af ctrl+F11.

Nu kan du vælge mellem applikationerne fra de foregående afsnit af Android-skolen i de tre faneblade:

Hermed er du færdig med den femte og sidste undervisningstime i Android-skolen.

»Ønsker man at ændre radikalt på funktionaliteten eller udseendet af tabs, er det desværre ikke helt ligetil. Da TabActivity er en specialisering af klassen ActivityGroup, kan man i stedet implementere sin egen ActivityGroup. I Gigbox har vi lagt tabs i bunden og indført vores eget tab-layout netop via denne metode,« siger Klaus Kartou.

Et skræddersyet faneblad-layout i Gigbox-applikationen. Her er de tre tabs placeret i bunden af skærmbilledet med egne ikoner. (Grafik: Gigbox).

»Et godt råd er at gennemtænke layoutet af ens activity, inden man går igang. Tegn eventuelt en tegning på et stykke papir og overvej, hvilke GUI-komponenter, der kan bruges til at indfri den,« siger Klaus Kartou.

Litteratur: [1] http://developer.android.com

Skab Danmarks bedste Android-applikation og vind en eksklusiv tur med alt betalt til verdens største mobilmesse i Barcelona. Deadline er 11. januar 2010. Læs mere på http://www.version2.dk/android

Send Tweet
Udskriv

IT-job & karriere

  • Se alle it-job
  • Importer din kompetenceprofil fra LinkedIn
Java J2EE udvikler ( J2EE )
Udgivet 23. nov 2011 13.43
Systemudvikler
Udgivet 6. feb 16.40
Java udviklere – Web-frontend
Udgivet 16. jun 2011 14.21
Forretningskonsulent
Udgivet 27. jan 10.11

Tilføj kommentar

Opret en konto eller log ind for at følge indhold på Version2 - og bliv opdateret via e-mail eller rss

Følg kommentarer
Log ind herunder eller opret en bruger for at skrive kommentarer
Du kan logge ind med din e-mail-adresse
Der er forskel på store og små bogstaver i adgangskoden.
Glemt adgangskode?

Seneste nyt

Teknologirådet reddet: Fortsætter i ændret konstruktion

Udgivet 10. feb 11.32Opdateret 10. feb 11.32

Version2 tester: Her kan du fare vild i Windows 8

Udgivet 10. feb 10.44Opdateret 10. feb 11.04

Rygte: Google snart klar med Dropbox-konkurrent

Udgivet 10. feb 10.19Opdateret 10. feb 10.19

Ny blog stiller skarpt på juraen i it-kontrakter

Udgivet 10. feb 10.00Opdateret 10. feb 10.15

Windows 8 Consumer Preview klar til download 29. februar

Udgivet 10. feb 9.49Opdateret 10. feb 10.24
Flere it-nyheder »
Få it-nyheder og blogs hver dag med Version2's nyhedsbrev.

Seneste debat

  1. Konklusion af Polsag-review fra 2009: Elendig kode hånd i hånd med elendig kontrakt

    12 comments.
    Last update 8 minutter 22 sekunder
    Skrevet af Robert Larsen
  2. Er it-skandalerne kontrakternes skyld?

    2 comments.
    Last update 36 minutter 35 sekunder
    Skrevet af Nicolai Dragsted
  3. Microsoft frigiver Android-version af OneNote

    7 comments.
    Last update 39 minutter 9 sekunder
    Skrevet af Thomas Bundgaard
  4. Derfor bliver dårlige it-projekter ikke stoppet i tide

    3 comments.
    Last update 52 minutter 14 sekunder
    Skrevet af Kasper Jørgensen
  5. 4 gode sikkerhedsråd: Sådan gør du firma-pc'en vinterferieklar

    5 comments.
    Last update 1 time 5 minutter
    Skrevet af Thomas Vestergaard
  6. XBMC på fit-PC3

    19 comments.
    Last update 1 time 7 minutter
    Skrevet af John Knuhtsen
  7. Stop SOPA, PIPA, ACTA, TPP og alle dem der kommer efter

    53 comments.
    Last update 1 time 19 minutter
    Skrevet af Jesper Lund Stocholm
  8. It skal spare kommunerne for 165 millioner kroner i 2012

    1 comment.
    Last update 1 time 19 minutter
    Skrevet af Christian Nobel
Mere debat »

Information

  • Kontakt redaktionen
  • Job- og annoncesalg
  • Teknisk support
  • Om Version2
  • Brugerbetingelser
  • Privatlivspolitik

Aktuelle emner

  • Agil udvikling
  • Android
  • Bruttolønsordning
  • Business Intelligence
  • Cloud computing
  • Digitaliseringsstyrelsen
  • HTML5
  • Harddisk-priser
  • IE9
  • Intranet
  • It-sikkerhed
  • Kindle Fire
  • Multimedieskat
  • NemID
  • OS X Lion
  • Open source CMS
  • Projektledelse
  • Scrum
  • Sharepoint intranet
  • Storage
  • Ubuntu 11.10
  • Virtualisering
  • Windows 8
  • Windows Phone 7
  • iOS 5
  • iPhone 4S

Tjenester

  • Android-app
  • iPhone-app
  • RSS-feeds
Følg @version2dk
Få it-nyheder og blogs hver dag med Version2's nyhedsbrev.

Version2 udgives af

  • Mediehuset Ingeniøren A/S work Skelbækgade 4 1717 København V
  • Tlf. work 33265300