Naar content
Trending apps
  • Inbox by Gmail

  • Maps: Navigatie en OV

  • WhatsApp Messenger

  • Messenger

  • Facebook

Trending games
  • Minecraft Earth

  • Dr. Mario World

  • Harry Potter: Wizards Unite

  • Breaking Bad: Criminal Elements

  • The Elder Scrolls: Blades

Trending smartphones
  • Samsung Galaxy Z Flip

  • Samsung Galaxy Note 10 Lite

  • Realme X2 Pro

  • Samsung Galaxy S20 Ultra

  • Moto G8 Plus

Nieuwste tablets
  • Samsung Galaxy Tab S6

  • Samsung Galaxy Tab A 10.5

  • Samsung Galaxy Tab S4

  • Samsung Galaxy Tab S3 9.7

  • Asus Zenpad 3S 10

DevTutorial 4 - Scrollview en Debuggen

· 21 september 2011

Welkom terug bij Android Programmeren. Dat je dit leest betekent dat je nog steeds geïnteresseerd bent in programmeren voor Android en als je de vorige drie DevTutorials hebt gedaan, ben je al een goed eind op weg. Vandaag gaat het over ScrollViews en Debuggen, vooral dit laatste is onmisbaar als je gemakkelijker wilt kunnen programmeren in Android. Waarschijnlijk snap je aan het einde van deze DevTutotorial zelf wel waarom dat zo is ; ).  Als verrassing heeft deze DevTutorial op het eind een extra oefening voor de fanatiekelingen, je leert hierbij hoe je verschillende ViewGroups en Views in elkaar bouwt, en hoe je xml shape-bestanden maakt en gebruikt in je Views.

Wat gaan we doen

In deze tutorial gaan we een simpele reken-app maken die de tafels uit kan rekenen van het getal dat je invoert. De app bevat een tekstveld waar je een getal in moet voeren en een knop waarmee je opdracht kan geven de tafel van het ingevoerde getal te berekenen. Wanneer de knop ingedrukt wordt, wordt de tafel van het getal berekent tot aan het getal 60: . Terwijl je deze app maakt (en de werking ervan gaat inspecteren) ga je de volgende nieuwe concepten leren:

  • ScrollView, hiermee kan je de Views die in de ScrollView zitten verticaal of horizontaal laten scrollen.
  • Method parameters, dit zijn berichten die je mee kan geven wanneer je een method aanroept.
  • Variables, de naam gebruikt wordt om te verwijzen naar het idee dat je waardes kan opslaan in het geheugen van het Androidapparaat.
  • For loop, dit is vergelijkbaar met een if block, behalve dat de code in een for loop meerdere keren uitgevoerd kan worden.
  • Logcat, een apart tekstscherm uit de ADT dat laat zien wat er in je emulator of Androidtoestel gebeurt.
  • Error tracing, dit is het inspecteren van de logcat en kijken wat voor foutmeldingen je tegenkomt.
  • Breakpoints, het aangeven van plekken in je code waar je wilt dat de app pauzeert zodat je kan kijken wat de bevroren toestand is van de app op een bepaald moment.

Dit is een DevTutorial waar je vaak gevraagd wordt het zelf ook na te doen, dus hij is best actief (en er wordt je, zoals je gewend bent, ook weer het nodige uitgelegd). Hier is de link naar de forum thread die bij deze DevTutorial hoort. Succes ermee!

De app ontwerpen: ScrollView

Door de mogelijkheden van de LinearLayout en de RelativeLayout te gebruiken is het je tot nu toe gelukt om al je Views in het scherm te tonen. Maar wat nou als je met geen mogelijkheid alle Views kunt tonen in hetzelfde scherm, terwijl het toch noodzakelijk is dat je de Views tegelijkertijd toont? In dit geval kan de ScrollView je helpen: de ScrollView is een layout die wanneer hij te groot wordt automatisch scrollbars krijgt en ervoor zorgt dat je de View die in de ScrollView zit kan scrollen. Zoals je misschien al verwacht, is een ScrollView een ViewGroup net zoals de RelativeLayout of de LinearLayout (als je het verschil niet meer weet tussen een gewone View en een ViewGroup, kijk dan even naar de vorige tutorial). Een beperking van de ScrollView is dat hij maar één View kan bevatten. Je kan deze beperking omzeilen door nog een andere ViewGroup te plaatsen in de ScrollView, en dan kan je vervolgens zoveel Views kwijt in die laatste ViewGroup als je maar wil. Een voorbeeld is dan dat een ScrollView een RelativeLayout bevat en dat de RelativeLayout dan meerdere gewone Views kan bevatten. Wanneer de RelativeLayout hoger wordt dan de ScrollView waar hij zit, dan krijgt de ScrollView automatisch scrollbars en kan de gebruiker de RelativeLayout scrollen. Voor het berekenen moet je een aparte method in je Activity maken die wordt uitgevoerd wanneer je op de knop (Button) drukt. De berekeningen die worden uitgevoerd worden weergegeven in een tekstveld waar je alleen tekst in kan tonen. In Android heet een tekstveld waarin je alleen tekst kan tonen een TextView, in de Graphical Layout Editor Tab kan je meerdere soorten TextViews gebruiken, waarvan de simpelste de naam Plain Text heeft (alle TextViews staan in de Graphical Layout editor tab links in het lijstje onder het mapje Text Fields). Doe nu het volgende:

  • Maak een nieuw Androidproject aan met deze en deze instellingen.
  • Verwijder de standaard layout (ga in het Package Explorer Window naar de map res/layout, klik met rechtermuisknop op main.xml en klik op Delete en vervolgens op Ok).
  • Maak een nieuwe layout aan, noem die scrollviewlayout.xml en selecteer als root element ScrollView: .
  • Er is nu een nieuw layoutbestand aangemaakt met daarin een SrollView als root element en daar is ook alvast een LinearLayout in geplaatst: . In plaats van een LinearLayout willen we een RelativeLayout gebruiken, dus de Linearlayout moet weg: klik in de Outline Window met de rechtermuisknop op de de LinearLayout en klik op delete zodat je layout er als volgt uit ziet: .
  • Zoals net beschreven moet je nu een RelativeLayout in je ScrollView plaatsen: Open scrollviewlayout.xml en zorg dat je de Graphical Layout Editor Tab voor je hebt. Zoek in de lijst die links van je layout staat naar de RelativeLayout en wanneer je hem gevonden hebt, sleep hem naar de Outline Window en laat hem los op de ScrollView regel. Sla je layout op zodat je scherm er nu als volgt uit ziet: .
  • Nu kan het lastig worden. Je kan nu niet zomaar een EditText of een andere View in je layout slepen: Eclipse denkt dan dat je EditText in de ScrollView wil hebben. Maar omdat je maar één View in de ScrollView mag hebben krijg je een foutmelding (of de actie die je wil doen wordt teruggedraaid door Eclipse). Daarom moet je erop letten dat je de Views die je erin sleept niet in de ScrollView plaatst maar in de RelativeLayout. Dit kan je gemakkelijker doen door de Views niet te slepen naar het zwarte scherm van de layout zelf, maar naar de outline van de layout die in de Outline Window staat. Sleep een EditText (dat is een Plain Text die staat in het mapje Text Fields) op het balkje van de Relative Layout in de Outline en laat hem daar los . Doe hetzelfde met een Button en een TextView (laat ze beide los op relativeLayout1 in de Outline Window) zodat je scherm er als volgt uit komt te zien: .
  • De Views die je net in de RelativeLayout hebt geplaatst moeten nu geordend worden. Zoals je in de vorige tutorial hebt geleerd moet bij een RelativeLayout van de Views aangeven waar ze ten opzichte van de andere Views geplaatst moeten worden:
ElementPropertyWaarde
ButtonId@+id/btnCalculate
ButtonTextBereken!
ButtonOn clickcalculateTables
RelativeLayoutPadding10dip
EditTextId@+id/etxtNumber
EditTextLayout to right of@+id/btnCalculate
EditTextText 
EditTextLayout widthfill_parent
EditTextInput typenumberDecimal
EditTextHintVoer een getal in
TextViewId@+id/txtvResult
TextViewLayout below@+id/btnCalculate
TextViewLayout margin top10dip
TextViewText\n
TextViewText size14dip
TextViewText color#FFFFFF
  • Je scherm moet er nu als volgt uit zien: (en vergeet uiteraard niet op te slaan, in het vervolg ga ik er vanuit dat je dat automatisch doet ;)).
  • Ga nu naar je class MainActivity die in het bestand MainActivity.java staat. Je ziet op regel 11 een fout staan: er wordt daarin verwezen naar de Layout main terwijl die niet meer bestaat. Los deze fout op; zorg ervoor dat naar juiste Layout wordt verwezen.
  • Definieer de volgende drie objecten zoals je ook in de vorige twee tutorials hebt gedaan: mBtnCalculate, mEtxtNumber en mTxtvResult. Dit moet je doen in het code block van je class MainActivity, boven de method onCreate. Tip: voor mTxtvResult moet je TextView gebruiken zodat je het volgende opschrijft: TextField mTxtvResult;
  • Importeer de bijhorende drie classes aan het begin van je class. Dit moet je doen net onder de package-declaratie. De package-declaratie is de eerste regel in je javabestand die aangeeft bij welke package(groep) je classhoort. Tip: voor de TextView moet je importeren uit android.widget.TextView: import android.widget.TextView;
  • Koppel de drie objecten die hebt aangemaakt aan de Views in je layout met de method findViewById. Dit moet je doen in de method onCreate, nadat de layout is geladen door de method setContentView aan te roepen (Als je dit namelijk doet voordat de layout is geladen dan kan Android de Views nog niet vinden). Tip: voor je TextView moet je volgende regel gebruiken: mTxtvResult = (TextView) findViewById(R.id.etxtResult);
  • Zoals is beschreven in de vorige tutorial zoekt Android naar de method calculateTables wanneer er op de knop mBtnCalculate wordt gedrukt. Dit komt omdat je in de layout de property On click van de button btnCalculate op calculateTables gezet hebt. Voeg deze method toe en controleer in je method of de ingedrukte View wel de juiste is (kijk voor tips anders naar de vorige DevTutorial). En vergeet niet de class View te importeren.
  • Je class moet er nu als volgt uit zien:

Toen je net de method calculateTables gebruikte, bereidde je de method er op voor om een berichtje te ontvangen bij het uitvoeren: de View die zojuist was ingedrukt. Zo'n berichtje wordt in Android een parameter genoemd: dit wordt in de volgende paragraaf uitgelegd.

App tussendoortje

Als tussendoortje wordt je uitgelegd wat method parameters en variables zijn. Je maakt hierbij meteen een kleine app zodat je goed door hebt dat je door middel van method parameters hetzelfde stukje geschreven code op verschillende manieren uit kan voeren. De hoofdrolspelers hierin zijn variables, die worden daarna als belangrijke achtergrondinformatie uitgelegd.

Method parameters

Parameters zijn berichten die je mee kan geven aan een method zodat je kan aansturen hoe de method wordt uitgevoerd. Zoals je waarschijnlijk nog weet is een method een verzameling van instructies (regels code) die samen een naam zijn gegeven en in een method block zijn geplaatst. Een voorbeeld van een simpele method is een method met één regel code:

  • Om dit beter te snappen gaan we als tussendoortje snel een kleine app maken: maak een nieuw Androidproject aan met deze instellingen: .
  • Voeg de bovenstaande method toe aan je class MainActivity, en voeg de benodigde imports toe:

De method zorgt ervoor dat er een korte tijd een zwart balkje getoond wordt met daarin de tekst: "Dit is een voorbeeldtekst die getoond wordt.". Deze method kan je uitvoeren door de naam ervan te typen gevolgd door een '(' en een ')' :

  • Voeg bovenstaande regel toe als laatste regel van de method onCreate in je class MainActivity en start de app.

Als je de app opstart zie je een korte tijd het balkje en daarin de tekst die je net hebt ingevoerd: . (als je de tekst niet ziet, druk in de emulator op de back knop en start de app opnieuw op vanuit het hoofdmenu in de emulator) Het lastige van bovenstaande method is dat het alleen maar handig is om hem te gebruiken als je een balkje wil met precies deze tekst: "Dit is een voorbeeldtekst die getoond wordt.". Als je een andere tekst zou willen tonen in een zwart balkje dan moet je een compleet nieuwe method schrijven. Dit is niet handig: je schrijft bijna precies dezelfde method, het enige dat je dan anders zou doen bij een andere tekst is een andere tekst schrijven tussen de dubbele aanhalingstekens:Zou het dan niet handiger zijn als je deze twee methods kan combineren en dat je de kleine verandering in het resultaat van de method op een andere manier kan aanpassen? Je zou dan op een of andere manier moeten laten weten dat het enige dat je anders wilt in het resultaat de tekst zelf is en dat je in alle gevallen van de method gewoon een zwart balkje wilt met daarin de aanpasbare tekst. Wanneer je de method aanroept, zou je eigenlijk een bericht mee moeten kunnen geven die aangeeft wat je als tekst wilt tonen in het zwarte balkje. Aan de andere kant zou je in de method zelf ook iets moeten aanpassen zodat je een bericht kan ontvangen en dat je deze vervolgens kan gebruiken in het aanroepen van het zwarte balkje. Berichten die je method kan ontvangen schrijf je tussen de haakjes die achter de naam van je method staan. In ons geval willen we een verzameling van letters/woorden als bericht kunnen ontvangen en zoals je weet heet dat in Android een String. Maar hoe kan je nou die String gebruiken terwijl je in je method bent? Net zoals je een Button een naam gaf en een EditText een naam gaf in je MainActivity in de vorige tutorials, moet je het bericht dat je ontvangt in je method ook een naam geven. Ook bij een method zeg je dat je het berichtje moet definiëren zodat je er later naar toe kan verwijzen. Het definiëren doe je op dezelfde plek waar je aangeeft wat voor berichtje je wil ontvangen: namelijk tussen de haakjes die achter de naam van je method staat. Dus stel dat we een method willen maken die een String als bericht moet kunnen ontvangen en we willen die String de naam message geven, dan doe je dat op deze manier:Elke keer als deze method wordt aangeroepen, zit in de String message het bericht dat getoond moet worden (want de String die tussen de haakjes staat, wordt elke keer bij het aanroepen van deze method opnieuw gedefinieëerd). De String message gebruik je dan meteen in de (enige) eerste regel van method: de tekst die eerst tussen haakjes stond is nu vervangen door de String message.

  • Pas de method makeToast in je class MainActivity aan zodat hij hetzelfde is als de nieuwe method die hierboven staat.

Wanneer je nu deze method aan wil roepen (vanuit bijvoorbeeld de method onCreate) moet je het extra bericht meegeven. Zoals je misschien kan raden doe je dat tussen de haakjes wanneer je method aanroept:Op deze manier kan je de method makeToast op oneindig veel verschillende manier gebruiken doordat je steeds een andere tekst meegeeft. Dit is veel handiger, omdat je nu niet voor elke nieuwe zin een aparte method aan hoeft te maken.

  • We kunnen nu onze kleine app afmaken: verwijder de laatste regel van je method onCreate en voeg er drie regels aan toe die allemaal de method makeToast aanroepen met een verschillend bericht:

Als je nu je app opstart, dan krijg je achter elkaar drie verschillende berichten, probeer dat zelf ook uit!

Variables

In de vorige paragraaf heb je een method gemaakt waarbij je de String message bij het aanroepen een andere inhoud van letters/woorden kan geven: hierdoor kan je door middel van de method makeToast verschillende teksten laten zien in een zwart balkje. Je zou kunnen zeggen:

  • De inhoud van de String message die verandert elke keer bij de uitvoering van de method makeToast.
  • Of: de inhoud van de String message varieert elke keer bij de uitvoering van de method makeToast.
  • Of: de inhoud van de String message is variabel.

Het Engelse woord hiervoor is variable en wordt om die reden veel gebruikt in Android. Een variable is dus een verwijzing naar een bepaalde waarde die je kan aanpassen en uit kan lezen. Een variable kan je definieren tussen de haakjes die horen bij het begin van een method block of gewoon 'los' op een willekeurige plek in een block zoals in een class block of in een method block zelf (beide voorbeelden ben je al meerdere keren tegengekomen). Een variable moet je altijd een naam geven voordat je hem kan gebruiken en je moet van tevoren ook altijd aangeven wat voor type het is. Wanneer je bijvoorbeeld een int hebt die je de naam 'number' geeft:dan heb je dus een variable van het type int met de naam number. Je kan een waarde erin stoppen door erachter een = teken te schrijven en daarachter de waarde:Je kan ook meteen de waarde opgeven:Of wanneer je een String hebt die je 'address' noemt:dan heb je een variable van het type String met de naam address. Daaronder zie je hoe je een waarde opgeeft voor de String address, en daaronder zie je hoe de variable met de naam city van het type String meteen een waarde Amsterdam krijgt. Op dezelfde manier kan je ook een TextView hebben die je txtvName noemt (of een TextView txtvAddress):dat noem je dan de variable van het type TextView met de naam txtvName, en daaronder zie je hoe de variable met de naam txtvAddress van het type TextView meteen een waarde krijgt, namelijk de TextView met het id txtvAddress die in de geladen layout is. Wanneer je het type beschrijft en daarachter de naam, dan reserveer je technisch gesproken ruimte in het geheugen van het Androidapparaat zodat je daarna een waarde erin kan opslaan. Afhankelijk van wat voor type je gebruikt, worden er meer of minder bits/bytes in het geheugen van je Androidapparaat gereserveerd (bits of bytes: 8 bits vormen samen één byte). Hoeveel dat is en wat het verschil is tussen een simpele waarde opslaan (een int, float, bolean, byte, short, long, double of void) en een Object opslaan (bijv een String, een TextView of een DatePicker, Activity) leer je in DevTutorial 7. Zolang je geen waarde toewijst aan een variable blijven alle gereserveerde bits op het getal 0 staan: bij een int of een float is dat gewoon het getal nul (dus 0), bij een Object noem je dat de speciale waarde null. Pas wanneer je een waarde toewijst met het = teken wordt de variable gevuld (technisch gesproken verander je dan eigenlijk de waarde: want 0 of null is op zichzelf natuurlijk ook een waarde). De rest van de tutorial gaat weer over de andere app: ScrollView Demo. Als je opdracht gegeven wordt iets aan te passen moet je dat nu weer in die app doen.

De app programmeren: for block

In het if block in de method calculateTables moet je de code schrijven die de tafels uitrekent en de uitkomst ervan laat zien in het TextView mTxtvResult. We willen de tafel uitrekenen van het ingevoerde getal tot aan het getal 60. Om dit te maken zou je 60 regels op kunnen schrijven die allemaal één van de 60 berekeningen uitvoeren. Met programmeren kan dit echter een stuk gemakkelijker. Je kan hiervoor het for block gebruiken. Het for block kan je zien als een uitbreiding op het gewone if block: ze beginnen beiden met haakjes waarin je een vraag kan stellen en vervolgens begint het code block. Maar wat anders is aan het for code block, is dat je binnen de haakjes ook kan aangeven hoe vaak het block uitgevoerd moet worden:Met bovenstaande for code block wordt 10 keer de tekst "hallo" op het beeldscherm getoond. Je kan de tekst binnnen de '(' en de ')' opdelen in drie stukken:

  1. int counter = 0 Dit stukje code wordt uitgevoerd aan het begin van het uitvoeren van het for codeblock: dit stukje gebruik je vaak om een getal aan te maken (of zoals net was uitgelegd, hier wordt de variable counter gedefinieerd van het type int en wordt de initiële waarde op 0 gezet).
  2. counter < 10 Dit is de vraag die steeds wordt gesteld; zo lang deze vraag met "ja" wordt beantwoord, wordt het code block opnieuw uitgevoerd. In dit geval is de vraag: "is het getal dat in counter zit kleiner dan 10?".
  3. counter++ Dit is wat moet gebeuren elke keer nadat het code block is uitgevoerd, in dit geval wordt elke keer nadat het block is uitgevoerd het getal opgehoogd met het getal 1 (het gebruiken van twee plusjes ++ achter een int met bijvoorbeeld de naam counter is een soort afkorting voor het schrijven van counter = counter + 1)

Wat je dan krijgt als dit code-block wordt uitgevoerd is het volgende:

  1. het code block begint: de int counter wordt aangemaakt en wordt op 0 gezet
  2. er wordt gekeken of het getal dat in counter zit kleiner is dan het getal 10. Het getal counter is nog maar net aangemaakt, en staat dus nog op 0. De vraag wordt dus met "Ja" beantwoord.
  3. Omdat de vraag met "Ja" wordt beantwoord, wordt het code block uitgevoerd, dat in dit geval enkel het tonen van de tekst "hallo" is.
  4. Het code clock is voor de eerste keer uitgevoerd, dus het getal counter wordt met 1 opgehoogd. Het getal counter heeft nu de waarde 1.
  5. Er wordt opnieuw gekeken of counter kleiner is dan het getal 10. Omdat counter nu op 1 staat, is dit nog steeds het geval en wordt het code block uitgevoerd.
  6. Er wordt voor de tweede keer de tekst "hallo" op het beeldscherm getoond.
  7. Counter wordt opgehoogd met 1, counter bevat nu de waarde 2.
  8. Counter is nu 2, en dat is nog steeds minder dan 10, dus het code block wordt opnieuw uitgevoerd.
  9. Voor de derde keer wordt er tekst op beeldscherm getoond.
  10. En dit gaat zo nog een tijdje door
  11. Maar wanneer op een gegeven moment counter 9 is en er is net tekst op het beeldscherm getoond, dan wordt counter opgehoogd naar 10.
  12. Vervolgens wordt opnieuw de vraag gesteld of counter kleiner is dan 10, maar dat is niet meer zo. Counter bevat het getal 10 en dat is evenveel als dat er gevraagd wordt.
  13. Het code block wordt dus niet meer uitgevoerd, Android gaat verder met het uitvoeren van de code die daarna komt.
  • Maak binnen de method calculateTables (en in het if block) een for block aan, en zorg dat die 60 keer wordt uitgevoerd (wat er precies in het for code block wordt uitgevoerd gaan we zo bespreken):

  • In het for block moeten de berekeningen uitgevoerd worden en wanneer deze klaar zijn moet het resultaat getoond worden in de EditText die je de naam mEtxtNumber geeft. Om het resultaat te kunnen bewaren gebruiken we een String die we allCalculationsResult noemen. Maak vóór het begin van het for code block (maar binnen het if code block) de String aan en geef hem een lege zin mee als startwaarde:

  • Voordat de berekeningen uitgevoerd kunnen worden moet ook nog het getal opgevraagd worden dat is ingevuld in mEtxtNumber. Anders weet je niet van welk getal je de tafel uit wilt rekenen. Dit doe je met de volgende regel:

Nu heb je een String waarin het getal staat dat is ingevoerd. Maar Android ziet de String niet als een nummer, maar als tekst, net zoals bijvoorbeeld de letter a of het woord hallo. Daar kan Android nog niet van raden wat voor getal het is. Je moet die String nog omzetten naar een getal, een int:

Je zou misschien denken dat je gewoon int number =(int) numberString;kan schrijven. Dit is echter niet het geval: een String is een heel ander soort variable dan een int: een int is een simpel type dat een getal kan opslaan tussen een bepaalde bandbreedte (tussen -2,147,483,648 en 2,147,483,648), terwijl een String een Object is waarbij de lengte van de woorden aanpasbaar is en je ook allerlei methods aan kan roepen op de String. Wanneer weet je dan wél of variables naar elkaar gecast kunnen worden? Dat heeft te maken met of de classes die je gebruikt superclass en subclass van elkaar zijn: je kan een class alleen casten als de bestemming class een superclass is, of als het object dat je gaat casten niet eigenlijk al een subclass-type is waar je het object naartoe wilt casten. Dit laatste is vaak het geval bij findViewById zoals geschreven in de vorige DevTutorial: je krijgt als resultaat een View terug, maar omdat je zelf de layout ontworpen hebt, weet je dat je te maken hebt met een specifiek subclass type zoals bijvoorbeeld een EditText of een DatePicker.

Nu kan je gaan rekenen met het getal. In java wordt een heel getal een int genoemd. Als je een getal wilt hebben dat ook getallen achter de komma's kan opslaan, dan moet je een float of een double gebruiken (en je moet dan Float.parseFloat(numberString); gebruiken). Je method calculateTables moet er nu als volgt uit zien:

  • Elke keer als de inhoud van het for block wordt uitgevoerd moet een berekening uitgevoerd worden. Om de uitkomst van de berekening te onthouden moet je een nieuwe int aan maken:

  • Om te weten met welke berekening we bezig zijn, kunnen we steeds kijken naar counter (dat getal dat begint bij nul en elke keer wordt opgehoogd). Om een berekening uit te voeren kan je hem gewoon opschrijven en plaatsen in de int die je net hebt aangemaakt (een '*' is in Android het teken voor vermenigvuldigen):

  • De drie getallen die samen je berekening vormen hoef je alleen nog maar uit te schrijven in een String zodat je die kan neerzetten in mEtxtResult:

Bovenstaande regel zou raar over kunnen komen: je gebruikt zomaar 3 ints (counter, number en result) en voegt ze samen met de karakters x en =. Dit is een handigheidje van Java: wanneer je een int samenneemt met een String (een verzameling van karakters), dan gaat Java er vanuit dat je de int ook wil gebruiken als een String en converteert hij de int automatisch naar een String (maar andersom werkt dit dus niet).

Als je de code nu zou uitvoeren dan wordt er 60 keer een berekening uitgevoerd. En die berekening wordt opgeslagen in de String calculationResult. Maar elke 60 keren als Android het for block uitvoert, worden alle variabelen (de int result en de String calculationResult) opnieuw aangemaakt. Dit komt omdat alle variables (variables is het Engelse meervoud van variable) die je aanmaakt, gekoppeld zijn aan het block waarin ze zijn gedefinieerd. Dus als Android buiten het block komt waar de variable in is gedefinieerd, dan kan je de variable niet meer opvragen (Android geeft dan een foutmelding dat hij niet weet wat je bedoelt met die variables). In programmeertermen heet dit de scope van een variable: deze is hetzelfde als het block waarin hij gedefinieerd is. Wat je dus moet doen om die uitkomsten van de berekening te onthouden is een String definieren die niet steeds opnieuw wordt aangemaakt, maar "door" blijft bestaan als er een nieuwe berekening uitgevoerd. Dit kan je doen door de String te definieren in het block dat om het for block heen zit: in dit geval is dat het if block. Dit heb je net al gedaan toen je de String allCalculationsResult aanmaakte. Omdat deze in een hoger gelegen block is gedefinieerd blijft allCalculationsResult bestaan en wordt hij niet opnieuw uitgemaakt bij elke nieuwe berekening. In programmeertermen zou je kunnen zeggen: het for block ligt in zijn geheel in de scope van de String allCalculationsResult.

Weet je nu ook waarom we de Views steeds definieren in het hoogst gelegen block van je class, namelijk in het block van de class zelf? Hierdoor is de scope van alle View variables net zo groot als het block van de class zelf: omdat alle method blocks en alle andere blocks die daar weer in zitten altijd in het class block zitten, zijn je Views variables overal in je class toegankelijk. Oh trouwens, ga nou niet meteen altijd alle variables in je class block definieren: je code wordt er rommeliger door (dit is een belangrijk argument) en het vergt onnodig veel geheugen. Probeer een variable altijd in een zo "laag" mogelijke scope te definieren.
  • Nu we de String allCalculationsResult hebben die altijd blijft bestaan in het for block, kan je die gebruiken om je resultaten op te slaan:

Wat je hier zegt, is dat je de inhoud van allCalculationsResult wil veranderen. En als inhoud geef je mee de oude versie van allCalculationsResult en daar achteraan plaats je de berekening die je net hebt uitgevoerd. Die \n in het midden staat voor een nieuwe regel: dus op deze manier worden alle berekeningen netjes onder elkaar gezet, gescheiden door een enter.

  • Het enige dat je nu hoeft te doen is de TextView mTxtvResult te vullen met allCalculationsResult. Zoals je misschien nog weet uit de eerste tutorials is de method setText de manier om de inhoud van TextView te bepalen:

Je method calculateTables moet er nu als volgt uit zien:In Eclipse is dat als volgt: . Let er even op dat de regelnummers precies gelijk zijn (dus maak of verwijder de benodige enters in je class), dit heb je straks nodig. Nu kan je de app opstarten. En wanneer je een getal invoert en op de knop drukt worden de tafels voor je uitgerekend: . Zoals je merkt wordt het scherm automatisch scrollbaar gemaakt omdat je een ScrollView hebt gebruikt.

De app debuggen

Wanneer je fouten gaat oplossen die in je app aanwezig zijn, heet dat debuggen. Zometeen gaan we de app expres laten crashen, maar om je daar even mentaal op voor te bereiden, vertel ik je eerst wat over een speciaal scherm die je na het crashen kan gebruiken voor bij het debuggen. Dit scherm heet het Debug Perspective: . Je kan hem openen door rechts bovenin het scherm op Debug te klikken of  op het plusje links van Java te klikken en Debug te kiezen als je Debug er nog niet hebt staan: (het plusje is aangegeven met een rood vierkantje). Wanneer je het Debug perspective opent, toont Eclipse de windows die je nodig hebt als je gaat debuggen (fouten opsporen). Wanneer je in het Debug perspective werkt, zie je in het midden het bekende Editor Window, rechts daarvan de Outline Window. Bovenin het scherm zie je drie nieuwe windows, opgedeeld in de linkerhelft en de rechterhelft. Links zie je het Debug Window: hier zie je tijdens het debuggen een overzicht van de actieve sub-processen (threads) die horen bij je app. Rechts zie je in tabjes ingedeeld de Variables Window en de Breakpoints Window. In deze tutorial wordt van deze windows alleen de Breakpoints Window uitgelegd. Onderin het scherm zie je het Console window, het Tasks Window en het LogCat Window. Alleen het LogCat Window wordt uitgelegd in deze tutorial: in het LogCat Window staat het technisch verslag van wat er in de Emulator gebeurt, opgeschreven in aparte regels tekst. Wanneer je het LogCat Window gebruikt kan je hem het beste groter maken door op het tabje van het LogCat Window te klikken en hem na gebruik weer kleiner te maken door er dan weer op te dubbelklikken. Wanneer je klaar bent met debuggen en je wilt weer verder coderen, dan kan je terug schakelen naar het Java Perspective door rechts bovenin het scherm op Java te klikken.

LogCat

Je zou kunnen zeggen dat je app prima werkt. Totdat je op een gegeven moment vergeet een getal in te voeren en op de knop Bereken! drukt. Dan krijg je dit scherm: . Het enige dat je nu weet is dat er "ergens iets is fout gegaan" (op zich ook wel logisch, als er een fout optreedt, ga je de doorsnee Androidgebruiker niet lastig vallen met ingewikkelde technische foutmeldingen waar hij toch niks van snapt). Als je wil weten wat er precies fout ging dan moet je kijken naar het LogCat Window: hierin staat een technisch verslag van wat er in de Emulator (of het aangesloten Androidapparaat) gebeurt. Als je daarna naar het Debug Perspective gaat en het LogCat Window groter maakt door op het tabje ervan te dubbelklikken,  dan zie je de foutmelding. We gaan nu de app laten crashen en vervolgens met LogCat uitlezen wat er fout ging:

  • Start de app in de emulator (of start de app opnieuw op vanuit het hoofdmenu in de emulator) .
  • Schakel in Eclipse naar het Debug Perspective, dubbelklik op de tabknop van de LogCat (aangegeven met een rood vierkantje: )  zodat deze groter wordt. Scroll in het LogCat Window helemaal naar beneden.
  • Ga nu terug naar je emulator en klik bijvoorbeeld op de terug-knop (back button) zodat je je app afsluit en naar het startscherm van de emulator gaat. Als je nu weer de app via het hoofdmenu van de emulator opstart zie dit terug als technisch verslags in de LogCat, hier aangegeven met een rood vierkant: . De bovenste regel in het rode vierkant "Starting activity Intent...." betekent dat de hoofd-Activity van je app wordt opgeroepen om te gaan starten. De onderste regel van het rode vierkant "Displayed activity me.moop.scrollviewdemo/.MainActivity" betekent dat je app opgestart is en getoond wordt (het kan zijn dat de middelste regel niet aanwezig is in jouw LogCat of dat er andere regels tussendoor staan).
  • Ga nu de fout waar ik het net over had opnieuw generen: zorg ervoor dat de TextView leeg is en klik op Bereken!. Je krijgt nu weer de fout, en in de LogCat wordt beschreven wat er fout ging: .

Wanneer je in de LogCat kijkt moet je altijd eerst kijken naar de fout die als eerste gegenereerd wordt, omdat de fouten die daarna komen vaak het gevolg zijn van de eerdere fout. De fout die als eerste gegenereerd is, staat bovenaan. Je ziet daar staan: Uncaught handler: thread main exiting due to uncaught exception. Dit bekent vrij vertaald in het Nederlands "er is een fout opgetreden en die is niet netjes verwerkt (afgevangen) door de app zelf, dus daarom wordt de app afgesloten". Deze foutmelding zie je in de LogCat verschijnen als je op je Androidemulator (of Androidtoestel) de popup krijgt met daarin: "Sorry! De toepassing X is onverwacht gestopt. Probeer het opnieuw" of in het Engels: "Sorry! The application x has stopped unexpectedly. Please try again". In de LogCat zie je daaronder een lange beschrijving met wat er precies is fout gegaan. Het begint met java.lang.IllegalStateException: Could not execute method of the activity". Vrij vertaald betekent dit: "de method kon niet worden uitgevoerd". Hier heb je nog niet zoveel aan. Daaronder staat een lange opsomming van hoe die fout tot stand is gekomen. Als je nog iets verder omlaag scrollt dan zie je op een gegeven moment staan Caused by: java.lang.reflect.InvocationTargetException. "Caused by" betekent zoiets als "veroorzaakt door". Dus de fout die helemaal bovenaan staat, is veroorzaakt door deze fout. Als je naar de regel daaronder kijkt dan zie je waar die fout is opgetreden: at nl.androidworld.scrollviewdemo.MainActivity.calculateTables(MainActivity:31). Dit betekent dat toen de hele ketting van deze foutmelding is geproduceerd, Android onder andere bezig was op regel 34 van MainActivity.java. Daaronder zie je nog een extra uitleg van de foutmelding: Caused by: java.lang.numberFormatException: unable to parse '' as integer. Deze fout gaan we verder onderzoeken door stap voor stap door onze code te lopen als hij wordt uitgevoerd. Dat kan je doen door middel van breakpoints.

Breakpoints: stap voor stap door je code heen lopen

Wanneer je met LogCat hebt uitgevonden waar de fout ongeveer zit, kan je breakpoints gebruiken om de uitvoer van je code rond de foute code te pauzeren en te kijken wat op dat moment de interne status van je app is. Wanneer je breakpoints wilt gebruiken moet je je app opstarten in Debug modus en moet je in je bestand AndroidManifest.xml aangeven dat je je app wilt kunnen opstarten in Debug modus. Wanneer je dat gedaan hebt, kan je breakpoints instellen in je code. In Eclipse kan je dit doen door een regel uit te zoeken waar je een breakpoint wilt plaatsen en dan op de rand van het Editor Window links ervan te klikken (op de plek waar de regel nummers staan). Dan verschijnt er een blauw bolletje in de linkerrand. Wanneer je je app vervolgens opstart in Debug modus en je app komt bij een regel waar een breakpoint staat dan wordt je app gepauzeerd en kan je kijken wat de waarde is van verschillende variables die in de scope zijn van de regel waar de breakpoint staat. Nadat je de variables hebt bekeken of andere Debug-dingen hebt gedaan kan je verder gaan met je code door weer op de play knop in het Debug Window te klikken. Andere optie is om regel-voor-regel door je code te stappen door de knoppen met de gele pijltjes te gebruiken uit je Debug Window. We gaan nu de fout uit de vorige paragraaf verder onderzoeken en vervolgens oplossen:

  • Dubbelklik eerst nog even op de tab van het LogCat Window zodat je Debug Perspective scherm er weer normaal uit komt te zien: .
  • Schakel terug naar het Java Perspective door rechts bovenin het scherm van Eclipse op Java te klikken.
  • Open nu het bestand AndroidManifest.xml, ga naar de Application Editor Tab en zoek naar Debuggable en zet die op true en sla vervolgens het bestand AndroidManifest.xml op: . Let er op dat je niet per ongeluk de AndroidManifest.xml van een andere app aanpast, maar dat je écht de AndroidManifest.xml van je ScrollView Demo app aanpast (ik weet hoe vervelend het is als je na een half uur zoeken ontdekt dat je in het verkeerde bestand dingen zat aan te passen en er daarom niks van merkte).
  • Ga nu  naar regel 31 van MainActivity.java, dubbelklik met de linkermuisknop op het regelnummer 31 zodat er een blauw bolletje verschijnt: (dit kan je trouwens doen in het Java Perspective maar ook in het Debug Perspective).
  • Schakel nu naar het Debug Perspective en klik op het insect-icoontje dat links naast de play knop staat: (aangegeven met een rood vierkantje).

Kijk naar het schermpje van MainActivity.java, deze staat links in het midden van het scherm. Ga nu naar regel 31 van MainActivity.java. Zoals je misschien nog weet is dit de regel waarop het de tekst die je hebt ingevuld in de EditText wordt omgezet naar een getal. Maar waarom krijg je dan een foutmelding? Om dit te onderzoeken, dubbelklik met je muis links van het regelnummer 34 (dus helemaal aan de linkerkant van het Eclipse scherm) zodat er een bolletje verschijnt: . Wanneer je de app uitvoert en Android staat op het punt deze regel uit te voeren dan wordt de app gepauzeerd.

  • Om de app te laten pauzeren op een breakpoint die je hebt ingesteld moet je de app op een speciale manier opstarten, namelijk in Debug mode. Dit kan je doen door op het insect-icoon te drukken dat links van het normale run-icoon staat: . Klik op de knop met het insect-icoon.
  • Je app wordt nu in Debug Modus opgestart. Om gemakkelijker te begrijpen wat er gebeurt, vul een getal in (bijvoorbeeld 67) en druk op Bereken!. Als je nu weer naar Eclipse kijkt dan zie je dat het uitvoeren van de app is gepauzeerd: . Dit kan je zien in het debug-schermpje waar bovenin staat Thread[<(willekeurig getal)>main] (Suspended (breakpoint at line 31 in MainActivity). Het woord suspended heeft in deze context betrekking op het feit dat de uitvoering van je app bevroren is. Daarachter staat tussen haakjes de reden hiervoor, in dit geval is de reden de aanwezigheid van je breakpoint op regel 31.
  • Als je nu met je muis stil blijft staan op numberString op het einde van regel 31 tussen de haakjes dan zie je het volgende: . Eclipse geeft een beschrijving van de String numberString. Je kan zien dat de inhoud van die String de twee karakters 6 en 7 is, en als je dit achter elkaar zet dan zie je 67. Android ziet dit niet als een getal, maar als twee karakters die toevallig achter elkaar staan. We moeten nog aan Android duidelijk maken dat we deze karakters samen willen gebruiken als een getal, oftewel een int. Dit heet parsen. Als je je afvraagt waarom die 67 hetzelfde is als 67 die je in de emulator hebt ingevuld in de EditText dan heeft dat te maken met de regel daarboven: op regel 30 heb je de inhoud van de EditText mEtxtNumber uitgelezen en in de String NumberString geplaatst. Wanneer zometeen regel 31 wordt uitgevoerd dan wordt de String NumberString omgezet naar de int die je number hebt genoemd. Klik op het debug-play knopje om de app weer verder te laten draaien: (zie het rode vierkantje, dit is dus een andere knop dan die je gebruikt hebt om in het begin de app op te starten). Je app wordt verder uitgevoerd zoals de bedoeling is en het resultaat van de berekening wordt weer getoond in het scherm van de emulator.
Ik wil je graag nog iets anders laten zien: voer opnieuw een getal in (bijvoorbeeld 84) en druk op Bereken!. Wanneer je weer in Eclipse bent als de uitvoering van de app is gepauzeerd, klik dan niet op de de Debug-Play knop, maar kijk op hetzelfde balkje als waar de Debug-Play knop op zit: daar zie je ook 3 knoppen met gele pijltjes naast elkaar staan: een pijltje dat met een hoek naar beneden wijst tussen twee streepjes, een pijltje dat met een boog naar beneden wijst over een streepje heen en een pijltje dat met een haakse hoek naar rechts wijst uit twee streepjes. Klik een paar keer op het middelste pijltje (die met een boog naar beneden wijst): hiermee geef je Android opdracht alleen de regel uit te voeren die op dit moment geselecteerd is. Als je dit bijvoorbeeld 10 keer doet dan merk je hoe Android door het for block heen gaat. Als je dan je muis stil laat staan boven counter dan zie je dat die steeds wordt opgehoogd bij elke iteratie. Je kan ook nu goed zien hoe de String allCalculationsResult stapje voor stapje wordt opgebouwd. Je hoeft trouwens niet persé je muis stil te hangen boven de variables: je kan ook rechts bovenin Eclipse in het Variables Window kijken. Als daar een variable geel wordt gekleurd betekent dat dat de waarde van de variable ten opzichte van de vorige stap veranderd is: .
  • We gaan nu kijken of we de fout van net opnieuw kunnen genereren. Zorg ervoor dat de EditText mEtxtNumber leeg is en druk op Bereken!. Als je in Eclipse nu weer met je muis stil blijft staan boven numberStringdan zie je dat hij leeg is: . Zodra je weer op de Debug-play knop drukt zal je app crashen: Android gaat namelijk proberen om een lege String om te zetten naar een getal. En dat kan niet.
  • Laat je app crashen --> Dit heb ik altijd al willen schrijven :). Wanneer de app nu crasht dan weet je waarom dat gebeurt.

try block & catch block(s)

Wanneer een uitzondering (exception) optreedt in je code dan moet je deze opvangen en verwerken. Als je dat niet doet, dan ziet Android dat als een fout (error): de code gedraagt zich dan immers op een manier waar hij niet door de programmeur op voorbereid is. De gebruiker krijgt dan zo'n "Sorry!" popup-scherm en de app wordt afgesloten. Wanneer je zo'n popup-scherm krijgt en je app wordt vervolgens afgesloten noem je dat in Android een forced close(een geforceerde afsluiting). Nu je weet wat er gebeurt kan je deze bug gaan fixen. Het opvangen van een uitzondering (in Android heet een fout een Exception) doe je in Android met twee blocks die je onder elkaar zet:In het try block schrijf je code die wilt proberen uit te voeren (vandaar het woord try). Wanneer Android een try block tegenkomt, begint Android gewoon met het uitvoeren van de code die in het try block staat. Maar wanneer er een uitzondering optreedt binnen een try block, dan springt Android door naar het catch block dat daaronder staat (de rest van je try block wordt dan niet meer uitgevoerd). catch is het Engelse woord voor vangen: in dit geval heeft dat betrekking op dat een catch block een uitzondering kan opvangen zodat er geen forced close komt. Wanneer je een catch block schrijft dan schrijf je in de haakjes achter het woordje catch wat voor soort uitzondering dit catch block op kan vangen. Bij het optreden van een Exception in het try block wordt gekeken welk type Exception het is, en vervolgens wordt per catch block gekeken of hij geschikt is om dat type Exception op te vangen. Het eerste catch block dat geschikt is om de Exception op te vangen wordt uitgevoerd en de uitzondering wordt in de variable e gestopt die gedefinieerd is tussen de haakjes. De rest van de catch blocks worden overgeslagen. Je kan dus ook meerdere catch blocks onder elkaar zetten:In bovenstaande code zie je drie catch blocks staan: eentje die een Exception opvangt van het type NumberFormatException, eentje die een Exception opvangt van het type SocketException en een catch block dat een Exception opvangt van het type IOException. Stel dat in het bovenstaande try block een uitzondering zou optreden, dan wordt eerst gekeken of het een Exception is van het type NumberFormatException. Is dat het geval, dan wordt het eerste catch block uitgevoerd en wordt de fout in de variable e gestopt die van het type NumberFormatException is. Is de fout niet van het type NumberFormatException dan wordt gekeken of het van type SocketException is of daarna of de fout van het type IOException is. Als voor alle catch blocks geldt dat ze de fout niet kunnen opvangen (het type fout is van een nog ander type) dan wordt alsnog een forced close gegeven: de fout werd dan immers niet opgevangen. We gaan nu de try - en catch blocks aanmaken:

  • Eclipse heeft een handige functie om deze try catch blocks automatisch in te voegen. Selecteer regel 29 t/m regel 40, klik er met de rechter muisknop op en klik op Surround With--> Try/catch Block: .

Eclipse analyseert nu je code vanaf regel 29 t/m regel 40 en kijkt wat voor Exceptions daar kunnen op treden. Vervolgens genereert hij automatisch catch blocks voor elk type fout dat in de geselecteerde code kan voorkomen. Je method calculateTables ziet er nu als volgt uit:Alle code die je net hebt geselecteerd staat in het try block.  Er is ook meteen een catch block aangemaakt. Tussen de ronde haakjes staat: NumberFormatException e. Dit betekent dat dit block alleen wordt uitgevoerd wanneer er een NumberFormatException is opgetreden. In gewoon Nederlands betekent dit: dit code block wordt alleen uitgevoerd wanneer er een fout is opgetreden die te maken heeft met een String die niet omgezet kan worden naar een getal. Deze NumberFormatException wordt de naam e gegeven. Hierdoor kan je binnen het catch block nog de foutmelding (die e wordt genoemd) bekijken en hier eventueel iets nuttigs mee doen. In dit geval word de method printStrackTrace aangeroepen: dit zorgt ervoor dat de foutmelding wordt doorgegeven aan Android en terecht komt in de foutmeldingen log.

  • Naast dat je app nu geen forced closed meer krijgt door deze bug wil je de gebruiker ook een melding van deze fout geven. Voeg onderstaande code toe in het catch block:

En vergeet uiteraard niet de benodigde import te doen. Tip: dit kan je heel gemakkelijk doen door stil te blijven staan met je muis op Toast en vervolgens de optie import Toast aan te klikken: .
  • Als je nu je app opstart en je vult niks in dan krijg je geen forced close meer, maar netjes een foutmelding: .
  • Nu de bug is opgelost kan je de breakpoint verwijderen: dit kan je doen door te dubbelklikken op het bolletje dat links van het regelnummer staat.

Extra oefening: shapes met een gradient

Op verzoek heeft deze DevTutorial een oefening voor mensen die nog verder uitgedaagd willen worden tijdens het programmeren voor Android. Bij deze oefening staan alleen hints over hoe je deze op kan lossen en er wordt geen theorie-uitleg gegeven. Kom je er niet uit dan kan je het internet gebruiken of kijken of het forum. Deze oefening gaat over de layout-hiërarchie uit de vorige DevTutorial en over het maken van een shape xml-bestand.
De titelbalk die we nu gaan gebruiken is eigenlijk niet mooi. Ook is het kleurgebruik van de app een beetje saai. We gaan hem opfleuren: .
  • Maak een nieuw layout-bestand en noem hem nicelayout.xml, selecteer als root element de LinearLayout.
  • Controleer dat de orientation property van de LinearLayout in je layout-bestand op vertical staat.
  • Voeg een RelativeLayout toe in de LinearLayout, en zet daarvan width op fill_parent en height op 44dip.
  • Ga naar de Source Code Editor Tab vanscrollviewlayout.xml en kopieer alles behalve de bovenste regel die begint met '<?xml version'.
  • Ga nu naar de Source Code Editor Tab van nicelayout.xml en plak de tekst die je net hebt gekopieerd achter </RelativeLayout> maar nog wel voor </LinearLayout> (Hierdoor plak je alles uit je oude layout in je nieuwe layout in de LinearLayout maar nog wel  ná de RelativeLayout).
  • Sleep een Text View ín de Outline Window ín de RelativeLayout, zet daarvan Text size op 16dip, Text style op bold, Text color op #ffffffText op ScrollView Demo en Layout center in parent op true.
  • Van de Text View die in je ScrollView zit (txtvResult), zet Text color op #333333.
  • Maak een nieuw Android XML File aan net zoals je zou doen wanneer je een nieuwe Layout wil maken (zie eventueel de vorige DevTutorial, kopje 'De app ontwerpen: LinearLayout'). Maar in het scherm wat daarop volgt, kies je bij "Wat type of resource would you like to create?" niet voor Layout maar voor Drawable, selecteer als root element een shape en kies als bestandsnaam blue_light_gradient.xml.
  • Kijk naar je Package Explorer Window, daar zie je nu een nieuwe map met de naam drawable met daarin het bestand blue_light_gradient.xml. Open het bestand en zorg ervoor dat dit erin komt te staan:
  • Maak opnieuw eenzelfde xml-bestand met de naam blue_intense_gradient.xml aan en vul hem met deze code:
  • Ga terug naar je layout-bestand nicelayout.xml en ga naar de RelativeLayout die je net hebt toegevoegd (de bovenste RelativeLayout) en zet Background op @drawable/blue_intense_gradient.
  • Van de ScrollView in je layout, zet Background op @drawable/blue_light_gradient.xml.
  • Ga naar MainActivity.java en zorg bij setContentView dat je nieuwe layout geladen wordt.
Als je nu de app opstart, krijg je dit: . Beetje jammer van die grijze balk bovenin he? Dat gaan we nu fixen:
  • Kijk naar je Package Explorer Window, open het bestand Androidmanifest.xml en ga naar de Application Tab. Zoek in dat scherm naar het veld Theme en zet die op @android:style/Theme.Light.NoTitleBar.
Als je nu je app opstart, is de balk weg en heb je een aardig mooie app: . In de twee shape xml-bestanden die je net hebt gemaakt kan je ook andere kleuren invullen om ermee te experimenteren (gebruik hiervoor bijvoorbeeld deze pagina). Wil je nog meer oefenen dan kan je proberen ervoor te zorgen dat de EditText en de Button niet mee scrollen als je de uitkomst van de berekening naar beneden scrollt.
Dit was het einde van deze DevTutorial. Hopelijk vond je het leuk te doen en heb je veel geleerd :) Als je vragen hebt over deze DevTutorial kan je hier terecht op het forum. Tot volgende week!

Source Code

Als je de sourcecode van deze app wilt bekijken kan je dat hier doen op github. Als je MainActivity.java wil bekijken, klik dan op scr --> me --> moop --> scrollviewdemo. Wil je de layoutbestanden bekijken dan moet je klikken op res --> layout en als je de xml shapes wil bekijken moet je klikken op res --> drawable.

Spelfouten, taalfouten of inhoudelijke fouten ontdekt? Stuur dan een mailtje naar de auteur van dit artikel!

Reacties (25)
Bezig met laden van reacties...