Samsung Galaxy S24: nu met hoge korting!

DevTutorial 5 – Internetverbinding en de AsyncTask

Wouter
28 september 2011, 20:45
29 min leestijd
DevTutorial 5 – Internetverbinding en de AsyncTask

Lees verder na de advertentie.

DevTutorial aflevering vijf. Langzamerhand begin je door te krijgen hoe Android werkt. Inmiddels heb je geleerd hoe je layouts maakt, hoe Eclipse werkt en hoe je daarmee kan debuggen. Ook heb je geleerd welke belangrijke blocks je kan gebruiken tijdens het programmeren zoals het if block, het for block en het try – en het catch block. Het is tijd om je programmeerkunsten te verbinden met het internet. Wanneer je je apps verbindt met diensten in de cloud kan je pas écht nuttige apps maken. Deze DevTutorial maakt een begin met het gebruiken van de internetverbinding. De DevTutorials die hierna komen bouwen daar op voort.

Wat gaan we doen

In deze DevTutorial gaan we een app maken die de gegevens van een Twittergebruiker downloadt en toont in een TextView: . Hierbij worden de volgende onderwerpen behandeld:

Als afsluiting van deze DevTutorial is er een extra oefening waarbij je meer leert over het opbouwen van een mooie layout door middel van enkel xml-bestanden. Herbij leer je over colors (kleuren), styles (stijlen) en de layer-list. Door op deze manier je layout op te bouwen hou je je layout overzichtelijk én schaalbaar.

kan je hulp vragen op het forum als je ergens niet uitkomt.

Veel succes weer gewenst!

De app ontwerpen en de basis programmeren

Omdat je nu steeds meer weet van Androidprogrammeren, worden de basiselementen die je nodig hebt voor deze DevTutorial in sneltreinvaart behandeld: in dit geval is dat het koppelen van de Layout en Views aan de code in je class inclusief de method voor het indrukken van een Button. Mocht het toch zo zijn dat iets je onduidelijk is dan kan je het beste de de vorige DevTutorials deels opnieuw lezen, afhankelijk van wat er onduidelijk voor je is.

ElementPropertyWaarde
RelativeLayout Padding 10dip
Button Id @+id/btnDownload
Button Text Download
Button Clickable true
Button On click downloadUserInfo
Button Layout align parent top true
Button Layout align parent left true
EditText Id @+id/etxtUsername
EditText Layout align parent top true
EditText Layout to right of @+id/btnDownload
EditText Layout width fill_parent
EditText Text  
EditText Hint twitter username?
EditText Input type text
ScrollView Layout below @+id/btnDownload
ScrollView Layout height fill_parent
ScrollView Layout width fill_parent
TextView Id @+id/txtvUserInfo
TextView Text Nog geen gebruikersgegevens bekend

[gist id=1041482]

[gist id=1041488]

Je class moet er nu als volgt uit zien: [gist id=1041312]

Kleuren in android: de TextView aanpassen

Kleuren in Android bestaan uit drie getallen, opgeschreven in de hexadecimale notatie waar elk getal uit twee cijfers bestaat, namelijk 0 t/m F. Dit kan je het beste begrijpen als 0 t/m 15, maar om te zorgen dat je geen twee tekens nodig hebt voor de getallen 10 t/m 15 worden in plaats daarvan A, B, C, D, E en F gebruikt. Deze drie getallen vormen samen een kleurnummer (of kleurcode), vandaar dat je het hekje # ervoor moet zetten. Een voorbeeld van zo een kleurnummer is #FF0000. Wanneer je deze kleur invult bij bijvoorbeeld de Color property van een TextView zet je de kleur van de tekst op rood. Eigenlijk voer je dan drie getallen in: FF,00 en 00. Dit zijn hexadecimale getallen en als je ze normaal zou schrijven zou je 255, 0 en 0 krijgen. Het eerste getal staat voor de roodwaarde van de kleur, doordat die op de maximale waarde FF(dus 255) is gezet is de kleur rood maximaal aanwezig. De twee getallen die daar volgen staan voor de groenwaarde en blauwwaarde van de kleur. Omdat de groenwaarde en de blauwwaarde op 0 zijn gezet, zijn die kleuren niet aanwezig. Als resultaat zou je met zo’n kleurnummer dan een puur rode kleur krijgen. Je kan proberen om als de app af is andere waarden te gebruiken voor de tekstkleur: #00FF00 voor Groen en bijvoorbeeld #0000FF voor blauw of  #FFFF66 voor geel. Je kan de kleuren ook op andere properties van Views invullen zoals bij de Background property of Text shadow property. In plaats van drie getallen kan je aan het begin van je kleurnummer nog een extra getal plaatsen: hiermee kan je de kleur transparant maken (zodat de kleuren die achter de view zitten deels doorschijnen). Hier moet je ook een hexadecimaal getal voor gebruiken: 00 staat voor compleet transparant (dus onzichtbaar) en FF staat voor compleet zichtbaar. 40 staat voor voor 25% zichtbaar, 80 staat voor voor 50% zichtbaar en C0 staat voor 75% zichtbaar. Wanneer je dan een rode kleur wil hebben die voor 75% zichtbaar is, moet je dus dit kleurnummer gebruiken: #C0FF0000. Wanneer je een roodkleur wil hebben die 100% zichtbaar is kan je #FFFF0000 gebruiken, maar dan kan je dus ook net zo goed #FF0000 gebruiken (want standaard is een kleurnummer van 3 getallen 100% zichtbaar). Vooral bij het einde van deze DevTutorial bij de extra oefening worden kleurcodes met transparantie veel gebruikt, let er dan alsjeblieft even op zodat je je bewust bent van wat je dan aan het doen bent.

ElementPropertyWaarde
TextView Color #FFFFFF
TextView Background #FF0066

Je layout main.xml moet er nu als volgt uit zien: .

De kleurstelling is nog niet optimaal op z’n zachtst gezet. Het ging er meer om dat je weet hoe je kleuren kan gebruiken in de layout. In één van de volgende DevTutorials die over opmaak gaat, leer je meer over kleurgebruik en styles.

De app programmeren

Voordat gegevens gedownload kunnen worden, moet de gebruikersnaam gecontroleerd worden, moet er een laad-schermpje getoond worden, moet er een internetverbinding Object worden klaargemaakt en moet je aangeven in het configuratie bestand van je app (AndroidManifest.xml) dat je de internetverbinding van het Androidtoestel wil kunnen gebruiken. Dat gaan we eerst doen. Als dat is klaargezet kan er worden begonnen met het programmeren van het downloaden van de gegevens van een Twittergebruiker. Omdat dat ietsje ingewikkelder is, is de tekst die daarbij hoort geplaatst in een apart onderdeel van deze DevTutorial. Dat onderdeel komt na dit onderdeel.

Methods aanroepen op een object: ingevoerde Twitter-gebruikersnaam controleren

Net zoals MainActivity methods heeft die je aan kan roepen zijn er veel andere zogenaamde Objects in Android waarvan je methods kan gebruiken. Een voorbeeld hiervan is het String Object waar je onder andere methods op kan aanroepen die je vertellen wat de lengte van het woord of de zin is die in de String zit of welk karakter er staat op op een bepaalde plek in de String. Vooral deze eerste kunnen we nu goed gebruiken: voordat gegevens van een twittergebruiker gedownload kunnen worden moet er überhaupt wel een Twittergebruiker ingevuld zijn. Of met andere woorden: de lengte van de String die je haalt uit etxtvUserName moet langer zijn dan nul. Om dit te controleren moet je eerst de tekst opvragen uit de EditText die we gebruiken onder de naam mExtUsername. Deze tekst wordt in een String gestopt: [gist id=1041481] Vervolgens controleren we op de String username of de lengte daarvan groter is dan nul, je vraagt dan dus eigenlijk: ”staan er meer dan 0 karakters in deze String die ik heb gevuld vanuit mExtUsername?”. Nu ga je iets nieuws leren dat belangrijk is: een String is net zoals een Activity een object waar je methods op kan aanroepen. Denk anders nog even terug aan de vorige DevTutorial waar je in het begin van je class Activity de volgende zin gebruikte: [gist id=1041476] Vervolgens werd in die DevTutorial uitgelegd dat je met de class MainActivity een kopie maakt van de class Activity en daarmee alle methods kan gebruiken die al aanwezig zijn in Activity. Op die manier gebruik je bijvoorbeeld nu in bijna elke DevTutorial de method findViewByID. En die method findViewByID kan je alleen maar gebruiken omdat je aan het begin van al je classes hebt beschreven dat je door wilt bouwen op de method Activity (dat doe je met het woordje extends): want in de class Activity zijn al een heleboel methods aanwezig zoals je hier kan zien. Nu weer even terug naar een String: wanneer je een String gebruikt in je code dan kan je daar methods op aanroepen die aanwezig zijn in de String. Het verschil tussen hoe je String gebruikt en hoe je Activity gebruikt is dat je een Activity van binnenuit gebruikt terwijl je een String van buitenaf gebruikt. Met Activity bouw je voort op de bestaande class en is het alsof je verder bouwt aan de class Activity (door middel van extends). Maar met een String bouw je er niet op verder, je gebruikt hem alleen maar. Een String aanmaken om hem daarna te kunnen gebruiken doe je steeds met: [gist id=1041472] Zoals je weet heb je dit al meerdere keren gedaan. Maar naast het feit dat je er karakters, woorden of lappen van tekst in kan stoppen kan je er ook methods op aanroepen waarmee je eigenlijk vragen stelt aan de String die je op dat moment gebruikt. Al de vragen die je aan een String kan stellen kan je op deze pagina vinden: java.lang.String. De vragen die je van buitenaf kan stellen staan onder het kopje public methods (methods die je alleen vanuit binnen kan aanroepen zijn protected methods, die zie je bijvoorbeeld bij de Activity class staan). Je ziet bijvoorbeeld staan charAt(int index) waarmee je kan vragen wat voor karakter er op een bepaalde plek in de String staat (en als extra bericht geef je dan mee van welke plek in de String je het wilt weten – dat is de int index die daarachter tussen haakjes staat). Op dezelfde manier staat er ergens length() en daarmee kan je vragen: wat de lengte is van de String? Ik ga het je nog ietsje verder uitleggen, maar als je dat aardig begrijpt dan ben je al best ver met Android, dus probeer nog even goed op te letten. Ergens in Android is door de makers van Android beschreven wat een String is. Toen ze beschreven wat een String is, hebben ze dezelfde woorden en syntax gebruikt die jij nu gebruikt om te coden. De makers van Android hebben toen een class gemaakt die ze String hebben genoemd (en hebben die geplaatst in de package java.lang). Om je een idee te geven zie je hieronder een klein deel van deze class staan: [gist id=1041376] Wanneer je dan in je code schrijft: [gist id=1239724] dan kijkt Android naar bovenstaande class (de beschrijving van de complete versie van die class vind je dus hier) en stopt een lege versie daarvan in username (in programmeertaal heet die lege versie null). Als je hem vervolgens vult met een tekst dan is die tekst opgeslagen in username, en daarna kan je ook de methods aanroepen die in de class staan. Bij bijvoorbeeld length() staat aan het eind van de method return count;. Dat betekent dat een berichtje terug wordt gegeven aan het stukje code dat de method length() opvraagt. In dit geval is de count een int, dat is dus een getal zonder cijfers achter de komma. Op dezelfde manier kan je ook de andere vragen stellen aan een String door de methods te gebruiken die bij String horen. Ik raad je aan om even naar de methods te kijken op de link die ik je net gaf: kijk bijvoorbeeld eens naar endsWith(String suffix) en indexOf(String string) en probeer te begrijpen wat ze doen. Nu kan je door middel van een if code block kijken of er een username is ingevuld en een foutmelding geven als dat niet zo is.

[gist id=1041383]

ProgressDialog: Bezig met het ophalen van gegevens…

Een ProgressDialog is een zwart rechthoekig schermpje met meestal een laad-boodschap (bijvoorbeeld “gegevens worden gedownload…”) die ervoor zorgt dat je gebruiker de app tijdelijk niet kan besturen. Deze ProgressDialog gebruik je wanneer je de gebruiker gedwongen wil laten wachten op een taak die op de achtergrond wordt uitgevoerd. Vaak is dat wanneer je gegevens aan het downloaden bent van het internet: dat is ook met onze app het geval wanneer we Twitter-gebruikersgegevens willen downloaden vanaf twitter.com. Voordat je een ProgressDialog kan gebruiken moet je hem een naam geven: je moet hem zo als dat heet ‘definiëren’. Dit moet je doen in het code block van je class. Als je dit namelijk doet in het code block van je method dan is hij voor Android niet zichtbaar in andere methods (dat is de scope van deze variabele). Dit terwijl je in een andere method je later opdracht moet geven om de ProgressDialog te laten verdwijnen.

[gist id=1041470] Vergeet niet de import te doen. Blijf met je muis hangen op het woordje ProgressDialog en klik op import ‘ProgressDialog’ (android.app). Nu kan je de lege ProgressDialog die je mProgressDialog genoemd hebt vullen met een nieuwe ProgressDialog en vervolgens de titel instellen en vervolgens hem tonen.

[gist id=1041466]

Je weet nu wel hoe je een ProgressDialog een tekst mee moet geven met setMessage en hem tonen met show, maar je weet nog niet hoe je hem moet laten verdwijnen. Verderop in deze DevTutorial wordt je uitgelegd dat je dat met hide method kan doen.

DefaultHttpClient (i.c.m. HttpGet & HttpResponse): de internetverbinding gereed maken

Met een Activity kan je controleren wat er op het scherm gebeurt door slim gebruik te maken van onder andere de methods onCreate, setContentView en findViewById. Met een String kan je letters opslaan en door middel van methods er vragen over stellen en opdrachten op uitvoeren (door onder andere de methods  length, indexOf en replace te gebruiken). Op dezelfde manier heb je de DefaultHttpClient waar je door middel van de method execute gegevens kan downloaden. Je kan de DefaultHttpClient het beste begrijpen als een soort tunnel naar het internet waar je een internet adres-aanvraag in kan stoppen en je een antwoord uit terug krijgt. De DefaultHttpClient kan nog veel meer dan alleen een internetpagina downloaden, daarom moet je best veel instellingen doen voordat je hem eenmaal kan gebruiken. Maar omdat we het nu alleen over het downloaden van een internet pagina hebben, gaan we het niet over de andere details hebben.

[gist id=1042325] (En vergeet niet om de imports te doen) Wat er precies gebeurt is nu nog te ingewikkeld om uit te leggen. Maar het belangrijke hiervan is dat er een DefaultHttpClient gemaakt wordt op de een-na laatste regel van het code block van deze method: DefaultHttpClient httpClient = ….. De regel daarna wordt deze DefaultHttpClient (die we httpclient genoemd hebben) terug gegeven als antwoord van deze method: return httpclient. Wanneer je nu in je class de method createHttpClient aanroept krijg je dus een DefaultHttpClient (een tunnel naar het internet) terug waar je aanvragen in kan stoppen en anwoorden uit kan krijgen. Een aanvraag heet een HttpGet en die kan je zo maken: [gist id=1042335] Vervolgens kan je die gebruiken in de method execute van de DefaultHttpClient en als resultaat krijg je daar een HttpResponse van terug: [gist id=1042442] Straks gaan we dit gebruiken in je class.

android.permission.INTERNET: toestemming hebben tot de internetverbinding

Om een internetverbinding (en andere speciale functies zoals gps, telefoonboek en vibratiefunctie) te kunnen gebruiken moet je dit aangeven in het bestand AndroidManifest.xml. Daarna pas stelt Android de internetverbinding aan jou beschikbaar. De reden hiervoor is dat bij het installeren van een app naar AndroidManifest.xml wordt gekeken om te kijken welke speciale toestemmingen (permissies) nodig zijn voor het uitvoeren van de app. De gebruiker moet hiervoor toestemming geven in het machtigingen-scherm als hij/zij de app installeert (dit heb je als Androidgebruiker waarschijnlijk al meerdere keren gedaan).

Voeg toestemming voor de internetverbinding toe in AndroidManifest.xml door de volgende stappen te volgen:

AsyncTask class

Om de volgende alinea voldoende te kunnen begrijpen moet je de volgende concepten je nog goed kunnen herinneren: subclass, overriden en extends. Weet je dat niet meer, lees dan eerst nog even de paragraaf “public class MainActivity extends Activity” uit DevTutorial 3.

Voor het downloaden van de gegevens van een Twittergebruiker moet je een speciale inner class (een class die je aanmaakt in het block van je hoofd-class) gebruiken die je subclasst op basis van de AsyncTask class, dat is een erg belangrijke class in Android. De AsyncTask class is een beetje ingewikkeld dus hij wordt in drie afzonderlijke paragrafen behandeld. De zin die nu komt wist je al: met je class MainActivity subclass je eigenlijk de class Activity en daardoor heb je onder andere de methods onCreateonPause of onDestroy die je kan overriden zodat je code kan schrijven specifiek voor die situaties (als de app wordt opgestart, gepauzeerd en afgesloten). Dit is ook van toepassing op de AsyncTask class: op dezelfde manier heeft de class AsyncTask de twee belangrijke methods doInBackground en onPostExecute die respectievelijk worden aangeroepen voor het uitvoeren van zwaar werk op de achtergrond én wanneer het uitvoeren van het zware werk voltooid is. Wanneer je deze methods overridet kan je code schrijven specifiek voor deze twee situaties: het uitvoeren van het zware werk op de achtergrond en wanneer het uitvoeren van het zware werk voltooid is. Wanneer dat is uitgelegd en je de inner class hebt aangemaakt wordt het uitvoeren van het zware werk geprogrammeerd: het downloaden van de gegevens van de Twittergebruiker. Daarna wordt de method ingevuld die wordt uitgevoerd wanneer het downloaden voltooid is, deze controleert op fouten en laat indien mogelijk de resultaten zien in de TextView.

Twee methods om een internetverbinding uit te voeren

Wanneer je via een internetverbinding iets wilt downloaden of uploaden kan je hier het beste de AsyncTask class voor gebruiken als hulpmiddel. Met de AsyncTask class kan je je code splitsen in een gedeelte dat op de achtergrond moet gebeuren en een gedeelte dat op de voorgrond moet gebeuren nadat het eerste gedeelte is uitgevoerd. Wanneer je alle code op de normale manier achter elkaar zou uitvoeren zou je app een tijdje onbestuurbaar zijn. Duurt dit onbestuurbaar zijn zelfs langer dan een paar seconden, dan denkt Android (omdat je app (tijdelijk) bevroren is) dat je app is gecrashd en probeert deze vervolgens te sluiten door middel van een vraag aan de gebruiker (“het proces X reageert niet meer, wilt u deze afsluiten?”). Naast het gebruik van de AsyncTask zijn bij het gebruiken van een internetverbinding de volgende drie punten belangrijk om rekening mee te houden: (1) het kan lang duren voordat je een reactie krijgt van de server waarmee je communiceert, (2) je weet niet zeker of je überhaupt wel verbinding hebt (3) en je weet niet zeker of je wel de juiste gegevens van de server krijgt. Het eerste punt kan je oplossen door de AsyncTask class te gebruiken. Deze class kan je maken in het code block van je eigen class. Voor nu is het handig om te weten dat je de class moet beschrijven door daar twee methods in te maken. Voeg onderstaande code toe onderin het block van de class MainActivity in MainActivity.java: [gist id=1040012] Wanneer je deze class maakt in de class die hem gebruikt, wordt je op twee manieren geholpen: de code die je in de method doInbackground schrijft, wordt in de achtergrond uitgevoerd en de code die je schrijft in de method onPostExecute wordt uitgevoerd wanneer de code van de method doInBackground afgelopen is. Wanneer je bijvoorbeeld Twittergegevens downloadt, zou je het downloaden van deze gegevens kunnen doen in de method doInBackground. Het vervolgens tonen van de gegevens (of een foutmelding als het anders gaat dan je dacht!) doe je in de method onPostExecute. De methods worden automatisch na elkaar opgestart, het enige dat je moet doen is AsyncTask zelf opstarten. Dat doe je met: [gist id=1042468]

[gist id=1042465] Nu wordt de AsyncTask opgestart wanneer je op de mBtnDownload drukt én er een gebruikersnaam is ingevuld. Wat er precies moet gebeuren in de DownloadUserInfoTask class, bepalen we in de volgende paragraaf.

Internetverbinding uitvoeren

Je hebt nu net een private class beschreven in je class MainActivity. Om deze class verder te gebruiken moet je een paar class variables toevoegen, net zoals je bijvoorbeeld steeds Buttons en TextViews definiëerde in de vorige DevTutorials.

[gist id=1042532] Nu gaan we de method doInBackground(Void … args) invullen: het internetadres waarvandaan gegevens gedownload moeten worden en het opstarten van downloadverbinding. Bij het opvragen van Twittergegevens moet je een url aanspreken waarin de username zit verwerkt. Dus je moet de username die is ingevuld in de EditText pakken en in een String stoppen. Daarna moet je special characters die in de string zitten encoderen zodat je ze kan gebruiken in je url. Het encoderen is het herschrijven van special characters naar een bepaalde standaardnotatie zodat je ze kan gebruiken in je url. Een spatie wordt bijvoorbeeld veranderd in %20 en een komma wordt bijvoorbeeld veranderd in %2C. Dit moet je altijd doen als je tekst gaat plaatsen in een url.

[gist id=1042534] Nu heb je de String encodedUsername waarin je username zit die is ingevuld met inhoud van de EditText mEtxtUsername, geëncodeerd naar de vereisten om hem te gebruiken in een url. Nu kan je de url opbouwen die je gebruikt om de gegevens te downloaden. De url die je hiervoor moet gebruiken is https://api.twitter.com/1/users/show.json?screen_name en daarachter de gebruikersnaam, zoals je hier kan lezen. Dit leidt ertoe dat we de complete url op de volgende manier kunnen maken,

[gist id=1042542] Je kan deze trouwens ook testen in je browser door bijvoorbeeld als username androidworld te gebruiken. In dat geval ga je in je browser naar bijvoorbeeld https://api.twitter.com/1/users/show.json?screen_name=androidworld (er hoeft niks geëncodeerd te worden omdat er geen speciale karakters in zitten). Vervolgens wordt de String fetchUrl gebruikt om de data op te vragen. Om de verbinding in te stellen wordt de method createHttpClient() gebruikt. Wanneer je deze aanroept, krijg je een DefaultHttpClient terug die je nodig hebt om de verbinding op te starten. Het tweede onderdeel dat je nodig hebt is een opdracht voor de verbinding die je uit kan voeren. In programmeertermen noem je dit een HTTP GET en in Android gebruik je daarvoor een object van het type HttpGet. Deze opdracht kan je aanmaken door een opdracht uit te voeren.

[gist id=1042544] De DefaultHttpClient (die je gebruikt onder de naam httpclient) en de Httpget (die je gebruikt onder de naam httpget) kan je nu samen gebruiken om de gebruikersgegevens te downloaden. Dit doe je door van de DefaultHttpClient de method execute te gebruiken en als bericht de httpget mee te geven. Als resultaat van het aanroepen krijg je een object terug dat van het type HttpResponse is, deze noemen we response. In normaal simpel Nederlands gezegd, krijg je dus een antwoord terug wanneer je de url aanroept en in Android wordt het Object HttpResponse gebruikt om dat antwoord op te slaan (want dat “antwoord” heeft speciale eigenschappen die je nodig hebt om verder te kunnen programmeren zoals je zo zult zien):

[gist id=1042545] De opdracht hierboven, dat is de opdracht die lang kan duren (daarom plaats je deze in een aparte method in een speciale inner class die ervoor zorgt dat je achtergrond taken uit kan voeren). Na deze regel wil je weten wat het resultaat is van de opdracht. Die kan je vragen door de method getStatusLine() aan te roepen op het HttpResponse object dat je gebruikt onder de naam response. Het resultaat van die vraag naar die method is een StatusLine Object die je statusLine noemt (het verschil tussen de namen zit ‘m in de hoofdletter S). En dat object heeft een method getStatusCode() die een int (dus een getal zonder cijfers achter de komma) teruggeeeft (alle methods van een StatusLine object kan je hier vinden, zoek even de method getStatusCode() op in die pagina om een idee te krijgen). Op basis van dat getal kan je bepalen of de download succesvol was of niet. Wij gebruiken in onze code alleen de getallen 200 en 404, maar er zijn er nog veel meer zoals je hier kan zien <– kijk daar even naar, en merk op dat het eerste getal van de response code (een 1,2,3,4 of 5) aangeeft wat voor soort response het is.  (Oh, en kijk ook even naar code 418 😉 ).

[gist id=1042549] Voor ons is het belangrijk te weten of de download succesvol was en dat is wanneer de statuscode het getal 200 is. Dat controleren we met een if code block waarna vervolgens het resultaat (de platte tekst) wordt uitgelezen in de String mResultString.

[gist id=1042550] In het uitvoeren van bovenstaande code kunnen fouten optreden, de Twitterserver kan bijvoorbeeld uitstaan (en dat gebeurt bij Twitter regelmatig) of de verbinding vanaf je telefoon kan eruit liggen. Het enige dat je moet doen met de code die ik net met je doorliep, is het inpakken in een try catch code block.

[gist id=1042554] Zoals je ziet zijn er twee catch-blokken die verschillende soorten fouten opvangen. Zoals je misschien nog weet van de vorige DevTutorials, worden de catch code blocks alleen aangeroepen als er een fout ontstaat tijdens het uitvoeren van de code in het try code block. In het uitzonderlijke geval van zo’n fout, wordt gekeken welke fout het meest lijkt op de soorten fouten die in de catch code blocks zijn beschreven. Het code block met de eerste de beste match wordt aangeroepen en vervolgens wordt de fout in de variabele gestopt. Vervolgens wordt die fout geplaatst in de variabele mConnectionException (als er geen match is gevonden crasht de app).

Resultaat van de internetverbinding verwerken

We hebben de DownloadUserInfoTask zo ingericht dat het resultaat van het zware werk van de method doInBackground wordt opgeslagen in drie variabelen: (1) de statuscode van de internetverbinding is opgeslagen in mStatusCode, (2) als de aanvraag succesvol was, wordt de gedownloade tekst opgeslagen in de String mResultString en (3) als er een fout was opgetreden, wordt die opgeslagen in mConnectionException. Nu kunnen we deze gegevens gebruiken in de method onPostExecute. Deze methode wordt aangeroepen als het zware werk gedaan is, dus je kan sowieso de ProgressDialog laten verdwijnen: [gist id=1042630] Het enige dat er nu nog verder moet gebeuren is: (1) controleren of statuscode gelijk is aan 200 en dan mTxtvUserInfo vullen met de mResultString, of anders (2) controleren of de statuscode gelijk is aan 404 en een melding geven dat de gebruiker niet bestaat, of (3) gewoon de statuscode weergeven of (4) de gebruiker informeren als er een fout was opgetreden tijdens de verbinding. Dit kan je doen met een if code block gevolgd door twee else if code blocks en daarna één else code block. Probeer dit zelf eerst te maken: door de method setText te gebruiken op mTxtvUserInfo en als parameter mResultString mee te geven kan je de tekst veranderen. En door te controleren of de statusCode groter is dan 0 kan je controleren of de statuscode veranderd is. Is dit niet het geval, dan was er een fout opgetreden en kan je dat in een Toast weergeven. Probeer dit alsjeblieft zelf eerst even, ga dus met je gedachten van de automatische piloot af als je daar op stond en kijk of je dit aan elkaar kan maken. Er is een aardige kans dat het je lukt met de kennis die je tot nu toe hebt opgedaan. Geprobeerd? Je method onPostExecute zou er als volgt uit kunnen zien: [gist id=1043686] Probeer niet meteen alles over te nemen van hierboven. Probeer eerst te kijken of je met je eigen code de app uit kan voeren. Als er crashes komen, probeer dan te kijken in de logcat bij het Debugger perspectief en probeer te begrijpen wat er gebeurt. Weet je niet wat je fout doet, neem dan stukje bij beetje de code van hierboven over in je method onPostExecute. Nu kan je je app opstarten in de emulator. Let er op dat wanneer je de gebruikersgegevens wilt downloaden bovenin in het Androidscherm van je emulator het interneticoon aangeeft dat je verbinding hebt. Heb je geen internetverbinding in je emulator, dan zie je waarschijnlijk als je de app uitvoert deze foutmelding: . Dit komt dus doordat je rechtsbovenin het icoontje ziet staan dat aangeeft dat je geen internetverbinding hebt. Heb je geen internetverbinding, sluit dan de emulator af door op het kruisje of het rode bolletje te klikken en druk opnieuw op run zodat de emulator opnieuw wordt opgestart. Vaak helpt dit om je internetverbinding in de emulator te activeren. Wanneer je de app werkend heb, kan je bijvoorbeeld dit als resultaat krijgen (afhankelijk van welke gebruikersnaam je invoerde): . Je ziet dat de gegevens niet netjes getoond worden: er staan komma’s, dubbele punten en andere leestekens doorheen. In de volgende DevTutorial gaan we een eigen class TwitterUser maken in een nieuw bestand TwitterUser.java. Daarin maken we onze methods getUsername en andere methods. Die methods gaan we gebruiken om de juiste gegevens op te kunnen vragen zodat we die in een mooie layout kunnen tonen.

Object(s): de belangrijkste bouwstenen van Android

Een belangrijk onderwerp in deze DevTutorial is het begrip Object. Wanneer je ook maar ergens in Android methods aanroept of laat gebruiken, horen die altijd bij een Object. Bij je MainActivity in deze DevTutorial worden bijvoorbeeld de methods downloadUserInfo en createHttpClient gebruikt. Op dezelfde manier gebruikte je in deze DevTutorial het Object DefaultHttpClient waarop je de method execute uitvoert en gebruikte je de method length op het Object String. Objects (dat is het engelse meervoud voor het engelse woord object) horen bij de belangrijkste bouwstenen in Android. Een String is een Object, een View is een Object, een Exception is een Object, een TextView is een Object, een HttpGet is een Object, een layout – of shape xml-bestand is uiteindelijk ook een Object in je code  en ga zo maar door. Je zult wel denken: wat heb ik er nou aan dat ik weet dat dit allemaal Objects zijn? Het belangrijke van een Object is dat hij methods bevat die je kan gebruiken wanneer je in Android programmeert. Dit is namelijk hoe Android is opgebouwd: een groot netwerk van Objects die met elkaar communiceren via methods. Zo heb je bijvoorbeeld het ActivityManager Object en die wordt aangeroepen door Android als de gebruiker aan heeft gegeven dat hij een app wil starten. De ActivityManager roept dan op een gegeven moment de method onCreate aan in je Activity zodat hij de controle geeft aan de programmeur die die method heeft geschreven (jij dus in dit geval). Het idee van Androidexpert zijn, is dat je precies weet welke Objects zweven op welke plek in Android en hoe ze met elkaar via welke methods communiceren. Als je dat weet, weet je precies wat er waar gebeurt op welk moment in het Androidsysteem. Ook weet je dan welke soorten functionaliteit op wat voor moment worden aangeroepen zodat je daar op in kan spelen met je eigen code en zo een crash-vrije en nuttige app kan maken. Vraag je af wat ik bedoelde met de laatste twee zinnen? Een simpel voorbeeld is het opvragen van GPS-coördinaten. Wanneer je in de toekomst meer kennis hebt van Android weet je dat je daarvoor de method getSystemService voor moet gebruiken in je Activity en dat je als resultaat van de method aanvraag een LocationManager object terug krijgt. Ook weet je dan dat je op het Object LocationManager de method requestLocationUpdates moet aanroepen om de GPS-coördinaten door te krijgen. Nu is het in werkelijkheid nog ietsje ingewikkelder, maar het idee blijft hetzelfde: des te meer je van Android weet, des te meer je weet van verschillende stukken functionaliteit hoe je ze moet gebruiken, welke Objects je daarvoor nodig hebt en welke methods je nodig hebt om die Objects met elkaar te kunnen laten praten. Wat is dan het verschil tussen een Object en een class? Een class is het ontwerp, de blauwdruk van het object. Of anders gezegd: een class is een bouwtekening: op basis van een class kan je een Object aanmaken in je code. Wanneer je dus bijvoorbeeld een DefaultHttpClient aanmaakt (zoals je deed in deze DevTutorial) dan schrijf je eigenlijk: ik wil een nieuw Object op basis van de DefaultHttpClient class. Het Object dat je dan hebt aangemaakt, is dan een Object van het type DefaultHttpClient (omdat je hem op de DefaultHttpClient class hebt gebaseerd).

Extra oefening: layer-list xml-bestand, @style, @color

Ook deze DevTutorial heeft een extra oefening. Bij deze oefening staan alleen hints over hoe je deze op kan lossen en er wordt minimale theorie-uitleg gegeven. Kom je er niet uit dan kan je het internet gebruiken of kijken op het forum. Eerst gaan we colors (kleuren) invoeren zodat we deze kunnen gebruiken als we layer-list xml-bestanden maken en styles maken (styles lijken een beetje op css-bestanden van html pagina’s). Een layer-list is een verzameling van afbeeldingen die op elkaar gestapeld worden zodat je dynamische achtergronden voor Views kan maken. Deze gebruiken we om een mooie titelbalk voor de app te maken. Als je deze titelbalk straks uitvergroot zie je dit: . Bovenin de balk is een lichte streep, in het midden is een gewone blauwe gradient en onderin is een donkere streep. Deze is gemaakt door drie afbeeldingen boven op elkaar te stapelen: een blauwe gradient, een half-doorzichtige gradient die boven wit is en onder zwart, en daar bovenop weer een blauwe gradient die boven en onder ruimte over laat zodat je boven een lichte streep ziet en onderin een donkere streep. Dit soort (schaduw) effecten zorgen ervoor dat je app er gelikt uit ziet. Styles zullen gebruikt worden om de TextView die in de titelbalk staat op te maken. De colors die je invoert worden door de layer-lists en de styles gebruikt. De styles en de layer-lists gebruik je vervolgens in je layout: .

[gist id=1247660]

[gist id=1247674]

[gist id=1247682]

[gist id=1247685]

Als je verder onder andere de layout_height van de RelativeLayout op 44dip hebt gezet, de juiste tekst hebt ingevoerd in de TextView en ervoor gezorgd hebt dat de TextView gecentreerd wordt gepositioneerd dan heb je nu dezelfde titelbalk als in deze screenshot: . Je kan nu proberen de rest van de layout na te maken door onder andere:

  • Een zelfde soort gradient te gebruiken voor de achtergrond van de app.
  • De achtergrond van de grote TextView een lichtere variant te geven van glare.xml.
  • De tekst in de TextView op te maken met een nieuwe style die je text_p noemt (deze kan je toevoegen onder de style text_h1 in design.xml).
  • Alle kleuren die je gebruikt in de app op te slaan in colors.xml .

De sourcecode van deze DevTutorial (zie volgend kopje) bevat al deze verbeteringen.

Sourcecode & Forum

De sourcecode kan je bekijken op github.

is de forum thread voor al je vragen die horen bij deze DevTutorial.

 

Op de hoogte blijven?

Volg Androidworld nu ook op WhatsApp

Download de nieuwe Androidworld-app!

Reacties

21

Inloggen of registreren
om een reactie achter te laten

26 augustus 2013, 17:17

Ik ben nu deze tutorial aan het doen, (lang nadat hij geschreven is) en dat is ook precies het probleem.
Op dit moment is de twitter api namelijk van 1.0 naar 1.1 gegaan waardoor de tutorial niet meer werkt…
heeft iemand de makkelijkste oplossing om dit op te lossen?

16 juli 2012, 12:43

Goede tut, maar ik kan niet vinden welke import ik moet doen om de internetverbinding actief te krijgen (http params).

Jeroen

10 februari 2012, 15:18

bij mij wil de applicatie de info niet laden. niet op mijn gsm en niet op de emulator.
aan wat kan dit liggen? help?

9 februari 2012, 16:41

Ter aanvulling. Ik run mijn applicatie op mijn mobile. Ook via browser op mijn mobile krijg ik deze meldingen.

urls in bovenstaande dienen aangevuld te worden met twitter_name

9 februari 2012, 16:37

Ik loop steeds tegen het probleem op dat ik een statuscode 400 terugkrijg. Ik heb nu beide urls gebruikt:

http://api.twitter.com/1/users/show.json?screen_name=
https://api.twitter.com/1/users/show.json?screen_name=
(twitter_name vervangen door echter naam)

Bij de http variant krijg ik continu een statuscode 400 en bij de https variant krijg ook een 400 met als melding “Rate limeit exceeded”. Nu heb ik echt niet meer dan 150 request verstuurd in een uur.
Bij de https heb ik een extra scheme toegevoegd met als port 443.

Iemand een idee wat ik fout doe of ligt het aan de url?

Alvast bedankt voor je reactie

25 januari 2012, 1:24

Sorry, had niet goed gekeken, maar zie dat de sourcecode beschikbaar is.
Mijn excuses

25 januari 2012, 1:21

Helaas heel wat fouten in MainActivity, kun je eventueel een volledige MainActivity posten? Zo kan ik beter controleren wat ik verkeerd heb gedaan.
Toch heb ik letterlijk alle bouwstenen met kopiëren/plakken uitgevoerd.

21 december 2011, 14:53

Sorry hij doet het weer.

21 december 2011, 14:51

DevTutorial 4 doet het niet!

Fatal error: Cannot use object of type WP_Error as array in /var/www/vhosts/androidworld.nl/httpdocs/wp-content/plugins/embed-github-gist/embed-github-gist.php on line 86

6 december 2011, 22:20

Leuke tutorials. Wel 2 kleine schoonheidsfoutjes:

1.
if (_view == mBtnDownload){
Je hebt de variabele ‘view’ aangemaakt en niet ‘_view’. Eén van beide zal aangepast moeten worden.

2.
Element Property Waarde
TextView Color #FFFFFF
Property heet Text Color i.p.v. Color

14 oktober 2011, 17:04

ik loop ook een weekje achter, maar ik vind het een prachtige tutorial! mijn complimenten!

8 oktober 2011, 2:53

Ik loop wat achter, maar hij is weer goed Wouter, dankjewel.
Op deze manier leer ik meer als in die standaard boeken die met de meeste saaie onzin eerst beginnen.

2 oktober 2011, 15:41

En hij was weer leuk! Wel al wat pittiger, maar het was ook de bedoeling om wat te leren 🙂 . Ik heb ‘m helemaal gedaan, kan de stappen in hoofdlijnen reproduceren en ga ‘m nu nog eens goed doorlopen om dat ook op detailniveau te kunnen doen. Wouter, ga zo door!

29 september 2011, 18:41

Wouter bedankt voor je rigorisme..

29 september 2011, 11:38

@Clemens Van Os
Komop man, je moet echt je zinnen beargumenteren, want op deze manier hebben je posts echt geen toegevoegde waarde. Post dan gewoon niet.

29 september 2011, 9:16

Fantastich AW. Hier is het allemaal om te doen.

29 september 2011, 4:05

Ik programmeer al zo’n 20 jaar, sinds meer dan anderhalf jaar ook op Android, en ik moet zeggen: petje af voor deze tutorials! Deze is eigenlijk de eerste die ik helemaal lees (de eerdere waren meer de fundamenten), en ik moet zeggen: heel grondig en gedetailleerd zonder dat ’t gaat vervelen. Leerrijk en een aanrader voor ieder die interesse heeft in Android development!

Toppie! Keep up the good work!

29 september 2011, 0:50

waar kan ik eerste tutorials herbekijken?

29 september 2011, 0:13

Thx

28 september 2011, 22:58

even bestuderen 🙂

28 september 2011, 22:58

Pfieuw, een korte 😛

Ga binnenkort (na de toetsweek :() maar beginnen aan 4 🙂