Handelswetenschappen en Bedrijfskunde - Geel Bachelor in de toegepaste informatica
Ontwikkeling van een Chinese educatieve tool voor Android
CAMPUS Geel
Olivier Nuyts
Academiejaar 2011-2012
2
VOORWOORD Toen we de kans kregen aangeboden om stage te lopen in het buitenland had ik mijn twijfels hierbij, aangezien we niet veel tijd hadden om te beslissen heb ik dit aanbod toen afgewezen. Enkele maanden later kwam de Katholieke Hogeschool Kempen met goed nieuws. Door een samenwerking met Hutong School, kregen een aantal studenten een nieuwe kans om stage te lopen in het buitenland. Daar ik spijt had van mijn eerdere beslissing heb ik mij onmiddellijk ingeschreven. Dit was een unieke kans vermits de stage zou plaats vinden in China en het de eerste keer was dat de KHK dit organiseerde. Nadat ik me had ingeschreven aan de Hutong School, kreeg ik mevrouw Corazzi toegewezen om me te helpen bij het vinden van een stage. Na een viertal maanden gezocht te hebben, heb ik de beslissing genomen om stage te doen bij Molatra. Ik zou graag van de gelegenheid gebruik maken om alle medewerkers van Molatra te bedanken. Klaus Maler, de baas van het bedrijf, heeft me de kans gegeven om mijn stage te lopen bij dit bedrijf. Ze hebben me ook een volwaardig IT-project toevertrouwd om aan te werken. Ik ben hen hiervoor zeer dankbaar. In het bijzonder bedank ik ook nog Craig McMahon. Hij heeft me tijdens dit proces op een professionele manier bijgestaan. Verder wil ik ook nog Filippo Bagnoli, mijn stagebegeleider bedanken. Hij heeft me nuttige raad gegeven bij het schrijven van dit eindwerk. Hij heeft me ook tips gegeven om de stage tot een goed einde te brengen. Ook wil ik de personen bedanken die er voor gezorgd hebben dat ik stage kon lopen in het buitenland. In het bijzonder Johan Smeuninx en de Hutong School. Zij hebben mij geholpen bij het regelen en zoeken van een stage bedrijf. Tot slot wil ik mijn ouders nog bedanken. Ze hebben me de kans gegeven om een buitenlandse stage te mogen ervaren. Hiervoor ben ik hen dankbaar.
3
SAMENVATTING Dit eindwerk is een uitgebreid verslag van een buitenlandse stage bij Molatra. Gedurende 13 weken heb ik gewerkt aan de ontwikkeling van een gloednieuwe applicatie voor Android. Een applicatie die dient om de uitspraak te leren van de Chinese taal. Bij de start van de stage kreeg ik de opdracht toegewezen en in grote lijnen werd me verteld waar de applicatie voor moest zorgen. Na het analyseren van deze opdracht ben ik aan de ontwikkeling van deze applicatie begonnen. Het belangrijkste element van deze applicatie is het werken met geluidsbestanden. Chineselistener kan men zien als een soort van mediaspeler die wordt gebruikt om Chinese woorden en hun vertaling met af te spelen. De taal waarin Android applicaties worden geprogrammeerd is het veel gebruikte Java. Deze programmeertaal heb ik ook gebruikt voor Chineselistener. Ik heb gewerkt in de ontwikkelomgeving Eclipse. Dit is het meest bekend als Java IDE(Integrated Development Environment). Het bevat onder andere een editor en een compiler. Het gebruikte databasesysteem is SQLite.
4
INHOUDSTAFEL VOORWOORD ..................................................................................................... 2 SAMENVATTING ................................................................................................. 3 INHOUDSTAFEL .................................................................................................. 4 INLEIDING ......................................................................................................... 6 1
MOLATRA ............................................................................................. 7
1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 1.4
Voorstelling.......................................................................................... 7 Team .................................................................................................... 7 Applicaties ........................................................................................... 7 Trainchinese desktop ................................................................................8 Chinese dictionary & flashcards ..................................................................8 Chinese Writer .........................................................................................9 Marktpositie ....................................................................................... 10
2
OPDRACHT ......................................................................................... 11
2.1 2.2 2.3 2.4
Aanleiding en achtergrond van het project ........................................ Verwacht resultaat............................................................................. Business case ..................................................................................... Doelgroep ..........................................................................................
3
ANALYSE ............................................................................................ 13
3.1 3.2 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.2.10 3.2.11 3.3 3.3.1 3.4 3.4.1
Chinese Listener ................................................................................ 13 Functionele eisen ............................................................................... 13 Het woorden leesvenster ......................................................................... 14 Help scherm .......................................................................................... 14 Audio lijsten .......................................................................................... 14 Afspelen ............................................................................................... 14 Meertaligheid......................................................................................... 15 Aantal .................................................................................................. 15 Frequentie ............................................................................................ 15 Geheugen vrijmaken .............................................................................. 15 Instellingen verwijderen .......................................................................... 15 Tijd tussen twee woorden ....................................................................... 15 Interactie met Trainchinese ..................................................................... 15 Database ............................................................................................ 16 Databasemodel ...................................................................................... 16 Voorbereiding bij de ontwikkeling van een Android applicatie ........... 17 Toestellen ............................................................................................. 17
4
UITWERKING ..................................................................................... 18
4.1 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4 4.4.1
Documentatie ..................................................................................... 18 Lay-out .............................................................................................. 18 Schermgrootte en dichtheid..................................................................... 18 Oriëntatie van het scherm ....................................................................... 20 Implementeren van lay-out ..................................................................... 20 Lay-out testen ....................................................................................... 23 Activity’s ............................................................................................ 24 MenuActivity ......................................................................................... 24 ListenerActivity ...................................................................................... 25 PreferencesActivity ................................................................................. 28 TrainchineseListsActivity ......................................................................... 31 Activity’s lifecycle ................................................................................... 33 Intent ................................................................................................... 37 Opslaan van gegevens ....................................................................... 38 SQLite .................................................................................................. 39
11 11 11 12
5
4.4.2 4.5 4.5.1 4.5.2 4.5.3 4.6 4.6.1 4.6.2 4.7 4.8 4.8.1 4.8.2
Shared Preferences ................................................................................ 42 Werken met audio bestanden ............................................................ 43 Downloaden .......................................................................................... 43 Splitsen en opslaan ................................................................................ 45 Afspelen ............................................................................................... 46 More en Less functie .......................................................................... 48 Algoritme .............................................................................................. 48 Implementatie ....................................................................................... 49 AndroidManifest ................................................................................. 51 Debuggen met Eclipse ........................................................................ 53 Logcat .................................................................................................. 53 Debug mode .......................................................................................... 54
BESLUIT…. ....................................................................................................... 56 LITERATUURLIJST ............................................................................................ 57
6
INLEIDING Gedurende 13 weken heb ik stage gelopen bij Molatra. Dit is software onderneming dat zich bezighoudt met het ontwikkelen van mobiele applicaties waarmee men Chinees kan leren. Molatra heeft momenteel al een aantal applicaties ter beschikking, de twee belangrijkste zijn Chinese Dictionary en Chinese Writer. Via deze applicaties kan men de betekenis van woorden opzoeken en of studeren en kan men ook de Chinese tekens leren schrijven. Een ander belangrijk onderdeel van het leren van Chinees is de uitspraak. Dit brengt me aan mijn opdracht namelijk het maken van een nieuwe mobiele applicatie dat zich focust op de uitspraak van Chinees. De applicatie is bedoeld om te draaien op een toestel met het besturingssysteem Android. In dit eindwerk heb ik het over de ontwikkeling van deze applicatie van begin tot einde. Na het lezen van dit verslag zal je te weten komen wat ik heb gemaakt en hoe ik daar aan gekomen ben. In het eerste hoofdstuk geef ik wat meer uitleg over mijn stage bedrijf. Waarom het bedrijf is opgestart en ook geef ik wat meer informatie over de applicaties die ze al hebben gemaakt. Vervolgens bespreek ik in detail hoe ze tot het idee van deze stage opdracht zijn gekomen en waarom deze zal aanslaan. De laatste twee hoofdstukken gaan over de uitwerking van de opdracht zelf. In hoofdstuk 3 vind je een uitgebreide analyse van mijn applicatie, hierin wordt vermeld hoe de applicatie er uit moet zien en aan welke functionaliteiten deze moet voldoen. Het laatste hoofdstuk gaat over de eigenlijke uitwerking van de applicatie. Hierin bespreek ik de belangrijkste elementen van mijn applicatie en hoe ik deze heb geïmplementeerd.
7
1
MOLATRA
Mijn buitenlandse stage heb ik gelopen bij de software onderneming Molatra in Beijing, China. In dit hoofdstuk ga je een beeld krijgen van wat Molatra is en wat het te bieden heeft.
1.1
Voorstelling
Molatra is een software onderneming dat zich bezighoudt met het ontwikkelen van applicaties die helpen bij het leren van Chinees. In 2003 is het bedrijf opgestart door Klaus Maler. Tien jaar geleden is hij naar China verhuisd en had geconstateerd dat het leren van Chinees in vergelijking met andere talen continue training nodig heeft. Hierdoor is het idee ontstaan om een bedrijf op te starten dat tooltjes biedt om het leerproces te vergemakkelijken. Het doel van Molatra is het creëren van toepassingen die studenten in staat stellen om op elk moment van de dag een leermiddel te hebben om deze taal te studeren.
1.2
Team
Molatra is een startend bedrijf en is daarom nog redelijk klein. Het team bestaat uit toegewijde professionals die ervaring hebben bij het leren van een vreemde taal. Het content team zijn professionele docenten van Chinese topuniversiteiten die ervoor zorgen dat de woorden en zinnen opgenomen in de applicaties correct en eenvoudig te begrijpen zijn. Deze docenten zijn gespecialiseerd in het geven van Mandarijn Chinees aan niet-native speakers van alle niveaus. Molatra is aan het groeien en willen nu ook de applicaties in verschillende talen uitbrengen. Hierdoor hebben ze een vertaalteam samengesteld die ervoor zorgen dat de woorden en uitdrukkingen die in de software worden gebruikt beschikbaar zijn in verschillende talen. Het software team bestaat uit niet-inheemse personen die interesse hebben in het leren van Chinees. Hierdoor kennen ze de moeilijkheden van het leren van deze tijdrovende taal en zorgen ze ervoor dat de toepassingen zo efficiënt en intuïtief mogelijk zijn.
1.3
Applicaties
Het bedrijf maakt applicaties voor Android, Iphone, Blackberry Tablet en ook voor op je desktop. Met deze applicaties kunt u Chinese woorden leren die Molatra ter beschikking heeft. Ze hebben een woordenboek van meer dan 50.000 woorden en is geconfigureerd in honderden verschillende lijsten zodat het makkelijker is om bepaalde gebieden te leren. Je kan zelf lijsten creëren en deze publiceren met andere gebruikers. De applicaties zijn geschikt voor absolute beginners tot veteranen van de taal. Omdat Molatra zich vooral bezighoudt met educatieve tools, besteden ze ook voldoende aandacht om de applicaties in meerdere talen beschikbaar te stellen. Momenteel hebben ze hun eerste applicatie vertaald naar het Spaans. In de toekomst willen ze dit uitbreiden naar het Frans en het Russisch. Molatra heeft in het totaal 5 verschillende applicaties. Ze zorgen ervoor dat hun applicaties op alle besturingssystemen beschikbaar zijn. Bij het merendeel van de applicaties is dit zo het geval. Hieronder volgt een korte bespreking van de belangrijkste applicaties die ze momenteel hebben.
8
1.3.1
Trainchinese desktop
Trainchinese Desktop is een flexibel en krachtig hulpmiddel om de Chinese lees-, schrijf-en luistervaardigheid te trainen. Hiermee kan je verbinding maken met de Trainchinese server om woordenlijsten met originele audio (opgenomen door native speakers) te downloaden en deze te oefenen. Je kan het programma automatisch woordenlijsten laten kiezen op basis van je leerniveau, of je kan er zelf selecteren. Het programma heeft vier verschillende modi voor het studeren van deze woorden.
Figuur 1.3.1 Tranchinese desktop
1.3.2
Chinese dictionary & flashcards
Met deze applicatie kan je duizenden woorden, voorbeelden, audio-opnames en karakter animaties leren. Het woordenboek bevat niet alleen woorden maar ook duizenden voorbeeldzinnen zodat je weet hoe woorden gebruikt moeten worden in een zin. Je kunt hiermee flash-kaarten maken of laten generen door de applicatie op basis van het geselecteerde leergebied. Een flash-kaart is een kaart waar het Chinese woord, Pinyin en Engels opstaat. Elke flash-kaart is in vier verschillende modi te testen op de verschillende aspecten van de Chinese taal. Dit wil zeggen, het Chinese teken, het Pinyin van dit woord of de vertaling ervan. Je kunt kiezen om de vertaling of het handschrift te studeren.
9
Figuur 1.3.2 Trainchinese Dictionary
1.3.3
Chinese Writer
Met Chinese Writer kan je op een spelende manier Chinese karakters leren schrijven. Wanneer je het spel start vallen er karakters van de bovenkant van het scherm, je moet ze dan vervolgens tekenen en zo kan je punten verdienen. Als de karakters de bodem bereiken verlies je een leven. Wanneer men er vijf heeft laten vallen is het spel gedaan. Na het spel kan je bekijken welke woorden je minder goed hebt gedaan, deze worden ook gemarkeerd en hebben een hogere prioriteit om later terug te komen.
Figuur 1.3.3 Chinese Writer
Dit spel is niet alleen bedoeld voor beginners, maar ook ervaren studenten kunnen hiermee hun schrijfniveau verbeteren. Karakters worden verdeeld in verschillende pakketten. Men kan kiezen uit deze verschillende pakketten of men kan er ook zelf samenstellen.
10
1.4
Marktpositie
Er zijn vele bedrijven die dezelfde tools aanbieden als Molatra. Toch heeft Molatra zeer veel succes. Hun belangrijke applicatie, Chinese Dictionary, is momenteel 100.000500.000 keer gedownload en hiermee komen ze in de top 10 van Chinese educatieve tools terecht. Wat maakt deze applicatie nu zo succesvol: •
•
•
Molatra gebruikt een eigen woordenboek, dit betekent dat ze continu nieuwe woorden toevoegen. Ook geven ze inhoud aan de woorden door voorbeeld zinnen toe te voegen. De nieuwe woorden die ze toevoegen worden geleverd met een geluidsbestand voor de uitspraak te horen, maar ook met een schrijf animatie om de schrijfvaardigheid te trainen. Dit houden ze voortdurend bij door audio op te nemen en schrijf animaties toe te voegen. De woorden die in het woordenboek staan zijn gecategoriseerd in meer dan 1000 verschillende lijsten. Dit kan gaan van Internationale relaties tot voetbal teams. Wanneer een gebruiker een idee heeft om een nieuwe lijst samen te stellen, kan hij dit melden aan Molatra, en dit wordt dan verwerkt in de database. Molatra werkt met flashcards. Een flashcard is een kaartje met een Chinees karakter op en de betekenis hiervan. De flashcard kan ook audio bevatten en de schrijf animatie. De gebruiker kan zelf flashcards samenstellen of kiezen van de database. Deze flashcards kan men organiseren in woordenlijsten. Deze lijsten kan men dan weer delen met andere Trainchinese gebruikers.
11
2 2.1
OPDRACHT Aanleiding en achtergrond van het project
Het bestuderen van een vreemde taal vereist veel tijd en uitermate veel toewijding, dit is vooral het geval met (Mandarijn) Chinees. Molatra houdt zich bezig met het ontwikkelen van mobiele applicaties om dit leerproces te vergemakkelijken. Deze leermiddelen helpen efficiënt uw studietijd te gebruiken. De producten worden voortdurend bijgewerkt om beter te passen bij de behoeften van de gebruikers. De educatieve applicaties van Molatra zijn de perfecte aanvulling voor elke student die Chinees aan het leren is. Met deze programma's kunt u een specifieke inhoud trainen die u zelf kiest. Molatra heeft zelf een woordenboek gecreëerd van meer dan 50.000 woorden en deze zijn onderverdeeld in honderden gegroepeerde lijsten om de gebruiker te helpen bij het leren van een specifiek onderwerp. De gebruiker kan ook zelf lijsten creëren, publiceren, en deze delen met andere gebruikers. De applicaties die Molatra biedt zijn gemaakt om een student die Chinees aan het leren is, van absolute beginner tot veteraan, te helpen. Men kan de betekenis van woorden opzoeken en of studeren en men kan ook de Chinese tekens leren schrijven. Een ander belangrijk onderdeel van het leren van Chinees is de uitspraak. Hierdoor is het idee ontstaan namelijk het maken van een nieuwe mobiele applicatie dat zich focust op de uitspraak van Chinees.
2.2
Verwacht resultaat
Het uiteindelijke resultaat van mijn stage zal een werkende mobiele applicatie zijn voor Android waarmee men al luisterend Chinees kan leren. Het is de bedoeling dat de applicatie op het eind van mijn stage beschikbaar zal zijn op de Android Market. Om te voldoen aan de eisen van Molatra, moet de applicatie bepaalde functionaliteiten hebben. Het belangrijkste aspect van deze applicatie is om comfortabel Chinees te kunnen leren. Eerst en vooral moet men een lijst van woorden kunnen kiezen op basis van het HSK niveau. HSK is onderverdeeld in drie categorieën: 1. Beginning level - HSK Basic (Level 1, 2, 3) 2. Elementary to intermediate level - Elementary (Level 3 - overlaps Basic Level 3, Level 4, 5); Intermediate (Level 6, 7, 8) 3. Advanced level - HSK Advanced (Level 9, 10, 11) Vervolgens kan men deze woorden en hun bijhorende vertaling laten afspelen. De gebruiker kan kiezen naar welke taal het Chinees wordt omgezet. Ook kan hij kiezen hoeveel keer het woord moet worden afgespeeld. Het is belangrijk dat de gebruiker voldoende mogelijkheden heeft om het volume en de pauzes tussen de woorden te beheren zodat men zeer comfortabel al luisterend Chinees kan leren. Andere vereisten zijn dat de gebruiker kan aanpassen hoe vaak bepaalde woorden worden afgespeeld. Het beeldscherm heeft 3 verschillende knoppen om dit aan te passen. Knoppen om het woord vaker af te spelen, minder vaak en niet meer af te spelen.
2.3
Business case
De Molatra applicaties zijn ontwikkeld door mensen waarbij Chinees niet hun moedertaal is en die zagen dat het Chinees, in vergelijking met veel andere talen, een continue training van vocabulaire en het leren van nieuwe woorden nodig heeft. Velen vinden dat de Chinese grammatica relatief gemakkelijk te leren is,
12
maar woorden en zinnen vereisen dan weer veel meer moeite. Het leren van de tonen, lezen en schrijven van Chinese karakters is ook een uitdaging die in geen andere Europese talen voorkomt. Molatra heeft geconstateerd dat repetitieve training en het gebruik van flashcards de meest effectieve hulpmiddelen zijn om deze taal te leren, maar er zijn maar weinig flashkaartinstrumenten die alle behoeften omvatten van de studenten die Mandarijn studeren. De programma’s van Molatra gebruiken deze twee methoden. Het doel van Molatra is het creëren van toepassingen die studenten in staat stellen onderweg of in hun eigen woning de Chinese taal te leren met behulp van de vele verschillende producten. Als het project succesvol afgerond is, zal het een meerwaarde bieden voor Molatra. Dankzij de applicatie zullen de gebruikers nog een extra tool hebben om Chinees te leren. Molatra zal hierdoor meerdere klanten aantrekken en dit zal voor meer omzet zorgen.
2.4
Doelgroep
De applicaties die gemaakt worden door Molatra zijn bedoeld voor mensen die Chinees willen leren. De mensen die voornamelijk met deze applicatie zullen werken zijn buitenlanders die in China komen wonen en de taal willen leren. Ook inwoners van China gebruiken deze applicaties omdat de taal zeer gecompliceerd is. Molatra wil in de toekomst ook scholen overtuigen, zodat zij de applicaties gebruiken bij de lessen Chinees. Hiervoor willen ze eerst een totaalpakket van applicaties maken zodat elk aspect van de Chinese taal kan behandeld worden. Dit pakket is pas volledig als mijn applicatie afgerond is.
13
3
ANALYSE
Bij het ontwerpen van een applicatie is het belangrijk om een duidelijk beeld te krijgen wat de mogelijkheden zijn van de uiteindelijke applicatie. In dit hoofdstuk verduidelijk ik de inhoud en de specificaties van mijn applicatie.
3.1
Chinese Listener
Zoals al eerder vermeld heeft Molatra al een aantal applicaties waarmee men Chinees kan studeren. Men behandelt hiermee alle aspecten van een taal, namelijk lezen, schrijven en spreken. Bij het leren van Chinees is uitspraak een heel belangrijk aspect. Er zijn woorden die men hetzelfde schrijft maar anders uitspreekt en hierdoor krijgt het woord een andere betekenis. De Chinese uitspraak kan men al oefenen met Trainchinese Dictionary. Dit is een applicatie van Molatra maar het is niet echt bedoeld om de uitspraak te trainen. Hierdoor is het idee ontstaan om een applicatie te maken waarmee men alleen de uitspraak kan oefenen. Het is daarom belangrijk dat dit audio aspect goed wordt uitgewerkt. Met Chineselistener zullen de studenten op een eenvoudige manier de uitspraak van woorden grondig kunnen leren. Een belangrijk aspect van Molatra applicaties is het werken met woordenlijsten. De bestaande gebruikers van Molatra hebben al woordenlijsten gemaakt om bepaalde leergebieden te oefenen. Het is belangrijk dat de gebruiker deze lijsten kan oefenen met Chineselistener. Hierdoor zal de applicatie niet helemaal los staan van de andere applicaties.
Figuur.3.1 Chineselistener logo
3.2
Functionele eisen
Zoals bij vele applicaties voor de smartphone is de lay-out ervan zo eenvoudig mogelijk gemaakt. Dit is ook zo bij Chineselistener. De interface is zodanig eenvoudig gemaakt dat de gebruiker geen moeilijkheden heeft om de applicatie te gebruiken. De gebruiker kan met één klik al Chinees studeren.
14
Figuur 3.2 Ontwerp luisterscherm
3.2.1
Het woorden leesvenster
Bij het afspelen van woorden wordt er een scherm weergegeven met het Chinese teken, Pinyin en de vertaling van het woord. De gebruiker kan naar het vorige of volgende woord gaan door met zijn vinger dit scherm naar links of rechts te bewegen. 3.2.2
Help scherm
Deze pagina vertelt hoe de gebruiker de applicatie moet gebruiken. Hierin wordt ook vermeld dat men via Trainchinese Dictionary woordenlijsten kan importeren. 3.2.3
Audio lijsten
De gebruiker kan kiezen uit lijsten met woorden om deze vervolgens af te spelen. De gebruiker kan kiezen uit officiële lijsten of zijn zelf gemaakte lijsten. De officiële lijsten zijn gebaseerd op het HSK niveau. Wanneer de gebruiker op een lijst klikt, is het de bedoeling dat men een bestand download van de server waar de woorden en hun betekenis instaan. Maar ook de geluidsbestanden die erbij horen. Deze woorden komen vanuit de Trainchinese database. 3.2.4
Afspelen
De gebruiker kan de lijst afspelen door op de afspeelknop te drukken, wanneer men drukt op deze knop wordt het een pauze knop waarmee de gebruiker het geluid kan stoppen. Na het afspelen van het woord wordt er automatisch een nieuw woord geselecteerd uit de lijst en wordt dit getoond en afgespeeld. Wanneer de gebruiker het scherm uitschakelt is het de bedoeling dat de woorden niet stoppen maar blijven doorspelen. Ook is het de bedoeling dat de gebruiker ondertussen andere applicaties kan gebruiken zonder dat het geluid stopt.
15
3.2.5
Meertaligheid
Wanneer de gebruiker op de afspeelknop heeft gedrukt wordt de Engelse vertaling van het Chinese woord eerst afgespeeld en vervolgd de Chinese uitspraak die bij dit woord hoort. Omdat men de database aan het uitbreiden is naar meerdere talen moet de applicatie voorzien zijn van meerdere talen. Zodat wanneer de vertalingen afgerond zijn, de applicatie onmiddellijk deze talen ook kan afspelen. De talen die deze applicatie gaat ondersteunen zijn Engels, Spaans en Russisch. De gebruiker moet ook de kans hebben om de volgorde van het afspelen te wijzigen. Standaard wordt het Engels eerst afgespeeld en daarna het Chinees. Dit moet gedaan worden aan de hand van een knop aan de onderkant van het scherm. 3.2.6
Aantal
De gebruiker kan instellen hoe vaak hij het Engels en Chinees hoort met behulp van de knoppen aan de onderkant van het scherm. Men kan ook kiezen om het Engels niet af te spelen dit doet men door het aantal van het Engels te veranderen naar nul. Het maximum aantal keer dat men een woord kan afspelen is vijf. 3.2.7
Frequentie
De gebruiker kan aanpassen hoe vaak bepaalde geluiden worden afgespeeld. Het woorden leesvenster heeft "meer" en "minder" knoppen. De betekenissen zijn "speel dit geluid vaker" en "speel dit geluid minder af". 3.2.8
Geheugen vrijmaken
Doordat de applicatie op elke device beschikbaar moet zijn en niet elk toestel evenveel geheugen heeft. Is het nodig om de gebruiker de kans te geven om lijsten die hij al kent of niet meer nodig heeft te verwijderen van zijn GSM. 3.2.9
Instellingen verwijderen
De gebruiker kan kiezen om woorden meer af te spelen dan andere. Men moet deze instellingen ook met één knop kunnen verwijderen. 3.2.10
Tijd tussen twee woorden
Het leerproces dat achter deze applicatie schuil zit, is dat de gebruiker even de tijd krijgt om over de vertaling of de uitspraak van het woord uit te zoeken. Deze tijd tussen het Chinese woord en de vertaling of visa versa moet kunnen gewijzigd worden. Het maximum is 4 seconde en het minimum is 1 seconde. 3.2.11
Interactie met Trainchinese
De gebruiker die deze applicatie gebruikt heeft hoogstwaarschijnlijk ook een account op andere applicaties van Molatra. Hierdoor bestaat de kans erin dat hij al woordenlijsten heeft samengesteld. Het moet mogelijk zijn om deze lijsten af te spelen via Chineselistener. Dit kan de gebruiker doen via twee methodes. 1. Men kan via de applicatie Chinese Dictionary een lijst selecteren en deze importeren naar Chineselistener. 2. Of men kan via Chineselistener inloggen op hun bestaande Trainchinese account met behulp van gebruikersnaam en wachtwoord. Vervolgens ziet men de woordenlijsten die deze gebruiker al heeft aangemaakt. Deze kan men dan afspelen via een klik op de lijst.
16
Omdat deze applicatie samenwerkt met Chinese Dictionary kan men naar deze applicatie openen via een knop onderaan het scherm.
3.3
Database
De applicatie bevat veel gegevens die moeten worden opgeslagen, hierdoor heb ik gekozen om met een database te werken. Android biedt volledige ondersteuning voor SQLite databases, hier maakt mijn applicatie ook gebruik van. Het database model dat ik heb opgemaakt en welke gegevens ik opsla staat in dit deel uitgelegd. 3.3.1
Databasemodel
De onderstaande afbeelding stelt mijn databasemodel voor.
Figuur.3.3.1 Databasemodel
De applicatie draait rond het afspelen van woordenlijsten. Hiervoor heb ik 3 tabellen aangemaakt, namelijk “playlist”, “playlistData” en “word”. In de tabel “playlist” sla ik de naam van de afspeellijst op, maar ook of de lijst woorden bevat die nog niet gedownload zijn. Ook slaag ik de hoeveelheid data deze geluidsbestanden in beslag nemen. De belangrijkste tabel in dit model is de tabel “word”. Deze tabel houdt alle gegevens bij van het betreffende woord. Als extra attributen heb ik nog range, count, played en missing toegevoegd. De attributen range en count worden gebruikt om de functionaliteit frequentie met te berekenen. Het attribuut “played” bevat het aantal keren het woord is afgespeeld, dit cijfer kan men in de toekomst gebruiken wanneer men statistieken wilt weergeven aan de gebruiker. Het laatste attribuut vertelt ons of er een geluidsbestand bij het bettrefende woord hoort. Het is namelijk mogelijk dat er voor sommige woorden nog geen audio is opgenomen. In de tabel “playlistData” hou ik bij welke woorden in welke afspeellijst voorkomen.
17
3.4
Voorbereiding bij de ontwikkeling van een Android applicatie
Bij het programmeren van een Android applicatie dient men eerst een aantal dingen te installeren. Een belangrijke keuze die men moet maken is in welke omgeving men gaat programmeren. Android-applicaties kunnen geprogrammeerd worden in verschillende ontwikkelomgevingen zoals Eclipse, Netbeans en Visual Studio. De meest gebruikte omgeving is Eclipse. Bij Molatra is dit ook de standaard ontwikkelomgeving. Ik heb er dan ook voor gekozen om hierin te programmeren. Eclipse is een gratis ontwikkelomgeving die bekend staat voor Java ontwikkeling. In de standaard versie van Eclipse kan men niet programmeren voor Android, hiervoor hebben we een Android Software Development Kit nodig. Deze SDK bevat een grafische tool, een editor en een compiler. Eclipse biedt de ondersteuning om plug-ins te installeren. Deze plug-ins zorgen ervoor dat Eclipse voor veel meer gebruikt kan worden dan alleen Java. Naast het installeren van de SDK is het ook een goed idee om de plug-in “Android Development Tools” te installeren. Deze plug-in zorgt ervoor dat men eenvoudiger kan programmeren voor Android. 3.4.1
Toestellen
Bij de ontwikkeling van mobiele applicaties heeft men een toestel nodig om de code te testen. Bij de installatie van de Android Development Tools zit een mobile device emulator. Deze emulator geeft je de kans om Android applicaties te testen zonder gebruik te maken van een fysiek apparaat. Bij Molatra heeft men naast deze emulator ook een aantal Android toestellen ter beschikking zodat men sneller kan testen.
18
4
UITWERKING
Na het analyseren van de opdracht ben ik begonnen aan de uitwerking ervan. Voor mij was ontwikkelen in Android iets nieuw. Hoe ben ik daar aan begonnen? In dit hoofdstuk leg ik uit welke stappen ik heb moeten doorlopen om tot een goede en werkende applicatie te komen. Dit hoofdstuk is onderverdeeld in 8 punten: -
4.1
Documentatie Lay-out Activity’s Opslaan van gegevens Werken met audio bestanden More en Less functie AndroidManifest Debuggen met Eclipse
Documentatie
Voor mij was het ontwikkelen in Android iets nieuws. Ik ben dan ook als eerste begonnen met meer informatie op te zoeken over de werking van Android applicaties. Android heeft een website, speciaal voor ontwikkelaars, ter beschikking gestelt waar men alle informatie kan vinden over het ontwikkelen van Android applicaties. Op deze website staan ook tutorials over verscheidene onderwerpen die aan bod komen wanneer men aan het ontwikkelen is. Als starter heb ik deze kleine tutorials doorlopen zodat ik een beetje vertrouwd kon worden met Android.
4.2
Lay-out
De allereerste stap bij het ontwikkelen is ervoor zorgen dat men een interface heeft. Het ontwikkelen van lay-outs in Android is een zeer lastige taak. Android draait namelijk op een groot aantal apparaten met verschillende schermformaten en dichtheden. Het is daarom van uitermate belang dat de applicatie die men ontwerp voor al deze toestellen uniform is. Android is hier van bewust, hierdoor biedt het systeem een ontwikkelomgeving aan om de lay-out voor deze verschillende apparaten gemakkelijk te ontwikkelen. Ook verricht het, het merendeel van het werk om de gebruikersinterface aan te passen naar de schermgrootte waarop de applicatie is geïnstalleerd. Het systeem biedt ook een API aan waarmee men controle heeft over de applicaties user interface(UI) voor de verschillende schermgroottes en dichtheden. Zo kan men de lay-out optimaliseren aan de verschillende scherm configuraties. Hierdoor kan men ervoor zorgen dat een UI voor een tablet er anders uitziet dan een UI voor een handset. Het systeem is instaat om de applicatie te vergroten of verkleinen afhankelijk van de schermgrootte. Men moet nog wel zelf een inspanning verrichten om deze technieken optimaal te kunnen gebruiken. Hierdoor zal het lijken of de interface ontworpen is voor de gebruikte schermgrootte in plaats van dat de lay-out gewoon uitgerekt is zodat het op de schermgrootte van het apparaat past. 4.2.1
Schermgrootte en dichtheid
Zoals al eerder vermeld biedt Android ondersteuning voor meerdere schermformaten en dichtheden. Je kan functies gebruiken van het systeem voor de gebruikersinterface
19
te optimaliseren. Ter vereenvoudiging heeft Android het bereik van de werkelijke afmetingen en dichtheden verdeelt in 4 algemene maten en 4 algemene dichtheden: • •
Maten: klein, normaal, groot en Xlarge; Dichtheden: ldpi, mdpi, hdpi en xhdpi.
Elke algemene grootte en dichtheid omvat een groep van werkelijke afmetingen en dichtheden. Figuur 4.2.1a toont de verschillende afmetingen en dichtheden die worden gegroepeerd.
Figuur 4.2.1a Verschillende afmetingen
Wanneer je nu de applicatie interface wil optimaliseren voor de verschillende grootte en dichtheden moet je ervoor zorgen dat je 4 verschillende lay-outs ontwerpt. In de praktijk betekent dit dat men 4 verschillende mappen maakt met daarin de verschillende lay-outs. Bij het uitvoeren van de applicatie zorgt het systeem er automatisch voor dat het de lay-out bestanden uit de map neemt dat overeenkomt met de omvang van het huidige apparaat. Voor de verschillende dichtheden is dit juist hetzelfde. Omdat de lay-out van Chineselistener bestaat uit verschillende afbeeldingen is het van belang dat deze niet verkeerd schalen op verschillende grootte. Hierdoor heb ik bij het ontwerp van de lay-out, de verschillende afbeeldingen moeten schalen naar de verschillende dichtheden.
Figuur 4.2.1b Mappenstructuur
Hiervoor heb ik 4 mappen aangemaakt, drawable-hdpi, drawable-ldpi en drawablemdpi. De lay-out bestanden die bijvoorbeeld gebruikt moeten worden voor de hoge dichtheid schermen gaan in de map “drawable-hdpi”. Bij het uitvoeren van deze applicatie op een apparaat met hoge dichtheid gaat het systeem automatisch het bestand nemen uit deze map. Het is belangrijk dat men de bestanden dezelfde naam geeft.
20
4.2.2
Oriëntatie van het scherm
Een smartphone heeft de mogelijkheid om het scherm te draaien, hier moet men rekening met houden omdat de breedte en hoogte van het scherm dan veranderd. Een smartphone applicatie heeft twee verschillende oriëntaties, namelijk landscape en portrait mode. Men kan ervoor kiezen om een andere bijpassende lay-out te gebruiken voor deze oriëntaties. In landscape mode wordt de breedte meer gebruikt, hiervoor moet je het bestand een beetje aanpassen. Ik heb een kleine aanpassing gedaan aan het luisterscherm omdat dit anders niet volledig werd weergegeven. 4.2.3
Implementeren van lay-out
Wanneer het ontwerp klaar was van Chineselistener heb ik dit vervolgens moeten implementeren in Android. Men kan dit doen op twee verschillende manieren: -
Met behulp van een xml bestand; Instantiëren van lay-out elementen in de programma code.
Men kan deze twee manieren ook combineren, ik heb ervoor gekozen om een standaard XML lay-out te maken voor elke activiteit en voor het wijzigen van lay-out elementen heb ik gebruik gemaakt van de tweede methode. Met behulp van een xml bestand Een xml bestand omvat de structuur van de lay-out en bevat ook alle elementen die zichtbaar worden aan de gebruiker. Een voordeel van deze methode is dat de code en de UI gescheiden zijn. Wanneer men aanpassingen doet in de lay-out hoeft je hierdoor niet meer code te wijzigen en opnieuw te compileren. Een voorbeeld hiervan is het maken van lay-outs voor de verschillende oriëntaties van het scherm. De XML vocabulaire is zodanig gemaakt dat het zeer hard lijkt op de methodes en de naamgeving van de klassen. Hierdoor is het makkelijk te raden wat een attribuut kan zijn. Het maken van deze XML bestanden is in het begin een beetje uitzoeken omdat de manier van werken anders is dan bijvoorbeeld het ontwerpen van een lay-out voor een website. Dit bespreek ik aan de hand van het lay-out bestand dat ik gebruik voor de weergave van het luisterscherm.
21
Figuur 4.2.3 Indeling lay-out
Bij het ontwerpen van zo een lay-out bestand is het handig dat men het scherm onderverdeeld in viewgroepen. Elke viewgroep kan meerdere lay-out elementen en of viewgroepen bevatten. Android beschikt over een aantal verschillende viewgroepen. De meest gebruikte zijn linearlayout, tablelayout, relativelayout , gridlayout en listview. • • • • •
Linearlayout: een viewgroep dat zijn kind elementen in een verticale of horizontale rij organiseert. Table lay-out: Een tabel lay-out met een willekeurig aantal rijen en kolommen. Relative lay-out: Hiermee kan je de locatie van onderliggende objecten instellen ten opzichte van elkaar. Grid view: Geeft een raster weer van kolommen en rijen die men kan scrollen. List view: Geeft een verticale lijst weer die men kan scrollen.
Bij het ontwerpen heb ik veelvuldig gebruik gemaakt van de linearlayout. Zoals je kan zien in het voorbeeld heb ik 4 viewgroepen. Als eerste hebben we het root element(groen). Dit is een groep van het type linearlayout. Het zorgt ervoor dat de kind elementen verticaal onder elkaar worden weergegeven. De overige groepen zijn ook van het type linearlayout, namelijk linearLayoutTop(rood), linearLayoutCenter(oranje) en linearLayoutBottom(geel). Ik bespreek hiervan de laatste viewgroep.
22
<Button android:id="@+id/buttonSwap" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_weight="0.02" android:background="@drawable/swap" android:onClick="@string/buttonHandler" /> Voorbeeldcode 4.2.3.1a Ontwerp van LinearLayoutBottom
Dit stukje code zorgt ervoor dat er onderaan het scherm twee tekstvelden en een knop komen te staan. De meeste attributen spreken voor zich maar layout_weight is toch iets speciaals. Men kan een bepaald “gewicht” aan een element toewijzen. Via dit element weet het systeem hoeveel ruimte hij aan het element mag geven. In dit voorbeeld gebruiken de twee tekstvelden evenveel ruimte en is de button iets kleiner. Om gebruik te maken van dit attribuut moet men wel de layout_width en of layout_height op 0dp zetten. Na het creëren van het XML document moet je het systeem nog laten weten wanneer hij dit moet gebruiken. Dit doen we door een stukje code toe te voegen bij het opstarten van een activiteit:
23
@Override public void onCreate(Bundle savedInstanceState) { Log.v("Class ListenerActivity[onCreate()]", "Creating ListenerActivity"); super.onCreate(savedInstanceState); setContentView(R.layout.main); } Voorbeeldcode 4.2.3.1b lay-out bestand instellen
Wanneer de activiteit wordt gestart is de methode onCreate() het eerse die het systeem uitvoert. Dit heeft te maken met de Activity’s lifecycle van Android, dit bespreek ik in het volgende punt. Vervolgens zorgt de methode setContentView() ervoor dat de ingestelde lay-out wordt geladen. Lay-out aanpassen via code Men kan ook de lay-out aanpassen in code. Het wordt gebruikt wanneer een lay-out dynamisch veranderd moet worden. Dit was bij Chineselistener ook het geval, de gebruiker kan de volgorde van de talen veranderen door op een knop onderaan het scherm te duwen. Bij het drukken van deze knop moeten er twee elementen veranderd worden van positie. De onderstaande code zorgt voor deze verandering.
public void swapLayout() { // swap layout LinearLayout languageLayout = ((LinearLayout) findViewById(R.id.linearLayoutBottom)); LinearLayout multiplyLayout = ((LinearLayout) findViewById(R.id.linearLayoutPlay)); View leftView = languageLayout.getChildAt(0); View leftViewM = multiplyLayout.getChildAt(0); View rightViewM = multiplyLayout.getChildAt(multiplyLayout .getChildCount() - 1); leftView.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, (float) 0.04)); View rightView = languageLayout.getChildAt(languageLayout .getChildCount() - 1); rightView.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT, (float) 0.04)); languageLayout.removeView(leftView); languageLayout.removeView(rightView); languageLayout.addView(rightView, 0); languageLayout.addView(leftView); multiplyLayout.removeView(leftViewM); multiplyLayout.removeView(rightViewM); multiplyLayout.addView(rightViewM, 0); multiplyLayout.addView(leftViewM); } Voorbeeldcode 4.2.3.2 Wisselen van lay-out elementen in code
4.2.4
Lay-out testen
Omdat Android over zoveel verschillende toestellen beschikt, is het van belang om je lay-out op zoveel mogelijke verschillende apparaten te testen. De Android SDK bevat een emulator om dit te doen. Via deze emulator kan men de verschillende apparaten
24
die het meest worden gebruikt virtueel toevoegen. Wanneer men specifiek wilt testen kan men deze virtuele toestellen(AVD’s) nog aanpassen aan een bepaalde dichtheid en of schermgrootte. Bij Molatra hebben ze een groot toestel en een klein toestel. Naast testen uit te voeren op deze toestellen heb ik ook gebruik gemaakt van de emulator. Voor het opzetten van deze test omgeving heb ik een aantal AVD’s aangemaakt. Deze virtuele machines kan men aanmaken in de AVD Manager.
Figuur 4.2.4 Android Virtual Device Manager
4.3
Activity’s
Na het implementeren van de lay-out kon ik aan het echte werk beginnen. Wanneer je in Android een nieuw scherm aanmaakt moet men werken met een Activity. Een Activity is een equivalent van een Graphical User Interface(GUI)/scherm. Een applicatie bestaat meestal uit meerdere activiteiten die samen werken met elkaar. Chineselistener bestaat uit 6 activiteiten namelijk: MenuActivity, ListenerActivity, PreferencesActivity, AboutActivity en TrainchineseListsActivity. Ik bespreek in dit hoofdstuk de belangrijkste activiteiten. Wanneer men een nieuwe activiteit aanmaakt moet men deze binden in het AndroidManifest.xml bestand. Dit bestand bevat al de settings van de applicatie. Hierover later meer. 4.3.1
MenuActivity
De menu activiteit is de hoofd activiteit van de applicatie, wanneer men de applicatie start, al dan niet van een andere applicatie, is dit het eerste scherm dat men te zien krijgt. Dit moet men ook vermelden in het Android manifest bestand. Hierdoor weet het systeem dat dit de toegangspoort is van de applicatie.
25
Figuur 4.3.1 MenuActivity
De gebruiker krijgt een menu te zien waarin hij kan kiezen welke lijsten met woorden hij wil oefenen. Ook kan hij via een knop naar het help scherm gaan. De lijsten die men kan kiezen zijn onderverdeeld in officiële en custom lijsten. Officiële lijsten: Wie Chinees aan het leren is zal op een gegeven moment zijn niveau willen testen. Dit kan met een officieel examen, namelijk het HSK examen. HSK staat voor "Hànyǔ Shuǐpíng Kǎoshì", het is een internationale Chinese toets voor buitenlandse leerlingen die geen Chinees als moedertaal hebben. Het examen is onderverdeel in 6 niveaus en deze officieel lijsten zijn hierop gebaseerd. Custom lijsten: De gebruiker kan ook kiezen om een custom lijst te studeren. Dit zijn lijsten die de gebruiker zelf heeft samengesteld of die zijn samengesteld door Molatra. De gebruiker kan deze lijsten importeren via de andere mobiele applicatie van Molatra of hij kan dit via de knop “Lists from my Trainchinese”. 4.3.2
ListenerActivity
Wanneer men een lijst heeft gekozen, komt men in de ListenerActivity. Dit is het belangrijkste scherm van de applicatie. Wanneer de gebruiker Chinees aan het leren is wordt dit scherm getoond.
26
Figuur 4.3.2 ListenersActivity en ListenersActivity in actie
Allereerst ziet men het Chinese teken, het Pinyin en de vertaling van het woord dat op die moment aan het afspelen is. Men kan naar het volgende/vorige woord gaan door dit schermpje te verschuiven naar links of rechts. Op dit scherm ziet men ook twee knoppen, “More” en “Less”. Als men hier op drukt komt het woord meer of minder voor. Met andere woorden als de gebruiker het woord beter begint te kennen zal hij op “Less” klikken, wanneer hij het nog niet kent op “More”. De gebruiker kan de veranderingen zien op de balk onderaan het schermpje. Als men op de afspeel knop drukt wordt de lijst afgespeeld. In dit voorbeeld zal eerst het Chinees worden afgespeeld en daarna het Engels. Men kan de volgorde wijzigen door op de “switch knop” te duwen. Wanneer het woord is afgelopen wordt er automatisch een nieuw woord getoond en ook dit wordt afgespeeld. Dit zal blijven duren tot wanneer de gebruiker op de pauze knop heeft geduwd. De gebruiker kan ook kiezen hoeveel keer het Chinees of Engels wordt afgespeeld. In het eerste voorbeeld wordt het Chinees 2 maal afgespeeld. De gebruiker kan dit wijzigen door op de knoppen naast het aantal te drukken. In de titelbalk ziet hij ook de lijst dat momenteel aan het afspelen is. Viewpager Voor het tonen van de woorden heb ik een viewpager gebruikt. Via dit element kan men horizontaal scrollen doorheen de woorden. Wanneer je een viewpager gebruikt moet je dit eerst declareren in het XML lay-out bestand.
27
Codevoorbeeld 4.3.2.1a Viewpager
Een viewpager haalt de verschillende soorten “schermen” vanuit een PagerAdapter. In dit geval zijn het altijd dezelfde schermen maar met een ander woord in. Deze adapter zorgt ervoor dat je volledige controle hebt over de verschillende “schermen”. De adapter heeft een aantal methoden dat dit werk vergemakkelijkt. Bij het ontwikkelen van mobiele applicaties is het belangrijk dat men rekening houdt met het geheugen dat de applicatie verbruikt, hierdoor heb ik de originele werking van de viewpager moeten aanpassen.
@Override public Object instantiateItem(View collection, int position) { View view = makeView(); ((ViewPager) collection).addView(view, position); return view; } Codevoorbeeld 4.3.2.1b Instantiëren van elementen
@Override public int getCount() { return 3; } Codevoorbeeld 4.3.2.1c Aantal elementen in een viewpager
Het eerste wat de viewpager doet is de schermen creëren die hij moet bevatten. Dit wil zeggen dat men bij de getCount() methode ervoor moet zorgen dat de viewpager weet over hoeveel schermen het gaat. Deze worden dan geïnstantieerd in de instantiateItem() methode. Omdat sommige lijsten meer als 1000 woorden bevatten heb ik de werkwijze moeten aanpassen naar mijn applicatie. Als eerste heb ik ervoor gezorgd dat de viewpager 3 schermen instantieert, ook al bevat de lijst meer als 3 woorden. Het eerste scherm is het “vorige woord”, het tweede scherm het “huidige woord” en het derde scherm het “volgende woord”. Wanneer de gebruiker nu naar het volgende woord scrolt gaat de viewpager niet naar het derde scherm zoals het oorspronkelijke idee van een viewpager is, maar gaat het altijd naar het tweede scherm. Hiervoor moet mijn code er voor zorgen dat de inhoud van deze schermen veranderen. Via dit hulpmiddeltje zorg ik ervoor dat de viewpager niet 1000 schermen moet creëren maar alleen maar van het vorige, huidige en het volgende woord. Een tweede voordeel hiervan is dat de gebruiker oneindig lang kan scrollen.
28
@Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeViewAt(position); } Codevoorbeeld 4.3.2.1d Verwijderen van element in een viewpager
Omdat het geheugen beperkt is bij mobiele applicaties is het nodig om de views die niet meer zichtbaar zijn te verwijderen. Dit stukje code behandelt dit probleem door elke view te verwijderen op die bepaalde positie. 4.3.3
PreferencesActivity
De applicatie bevat ook een menu om de instellingen te wijzigen. Hierdoor kan de gebruiker de applicatie veranderen naar zijn of haar noden.
Figuur 4.3.3 PreferencesActivity
Op elk Android toestel staat een knop om naar instellingen te gaan. Wanneer men op deze knop duwt komt men op dit scherm terecht. Het systeem is niet zo slim genoeg om te weten welke activiteit hij dan moet openen, dit moet men zelf implementeren. Dit kan je zien in onderstaande figuur.
29
@Override public boolean onCreateOptionsMenu(Menu menu) { Intent settingsActivity = new Intent(getBaseContext(), PreferencesActivity.class); settingsActivity.putExtra("menuActivity", true); startActivity(settingsActivity); return super.onCreateOptionsMenu(menu); } Codevoorbeeld 4.3.3a Starten van de PreferencesActivity
Het configuratie scherm is onderverdeeld in twee delen. Het eerste deel gaat over de instellingen die men kan doen aan de audio en het tweede deel gaat over de data. Audio settings: De gebruiker kan het volume regelen van de audio. Als men deze balk meer naar rechts verschuift zal de vertaling van het Chinees luider afspelen dan het Engels en visa versa. Het is ook mogelijk om de pauze te bepalen wanneer de applicatie de vertaling van het woord afspeelt. Deze instellingen worden opgeslagen zodat de ListenerActivity deze kan oproepen. Hierover meer in het puntje “Opslaan van gegevens”. Data settings: Het is van belang bij mobiele applicaties dat men de data die de applicatie gebruikt kan beheren omdat men meestal niet over zoveel geheugen beschikt. Hierdoor is het mogelijk om de data op te slaan op de SD card of in het interne geheugen. Deze instelling zorgt ervoor dat de data die in de toekomst wordt gedownload op het geselecteerde opslag medium opgeslagen wordt. Ook wordt de oude data verplaatst naar het geselecteerde medium. Het onderstaande stukje code bevat de belangrijkste methode van dit proces.
30
public static void copyFolder(File src, File dest) throws IOException { if (src.isDirectory()) { // if directory not exists, create it if (!dest.exists()) { dest.mkdir(); } // list all the directory contents String files[] = src.list(); for (String file : files) { // construct the src and dest file structure File srcFile = new File(src, file); File destFile = new File(dest, file); // recursive copy copyFolder(srcFile, destFile); } } else { // if file, then copy it // Use bytes stream to support all file types InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest); byte[] buffer = new byte[1024]; int length; // copy the file content in bytes while ((length = in.read(buffer)) > 0) { out.write(buffer, 0, length); } in.close(); out.close(); } } Codevoorbeeld 4.3.3b Kopiëren van bestanden
Deze methode heeft twee parameters nodig om te functioneren, namelijk de folder van de geluiden waarin ze momenteel zijn opgeslagen en de folder naar waar ze moeten gekopieerd worden. Na het kopiëren word de oude folder verwijderd. Voor ik deze methode uitvoer wordt er gecontroleerd of er wel degelijk een SD card aanwezig is en of er nog genoeg plaats beschikbaar is. In dit deel kan de gebruiker ook lijsten beheren. Men kan lijsten verwijderen van de telefoon, maar men kan ook het aantal keer dat bepaalde woorden voorkomen resetten. Dit kan door op de knop “Reset” te drukken, men kan deze ook apart resetten door op de afspeellijst te klikken. Dit opent een nieuw scherm waar men de woorden kan bekijken van die afspeellijst. Hier kan men per woord kiezen of het meer of minder moet worden afgespeeld. Door op de knop “Verwijderen” te klikken worden de database entries en ook de audiobestanden verwijderd. Omdat woorden in meer dan één lijst kunnen voorkomen, moest ik ervoor zorgen dat alleen die woorden dat eenmaal voorkomen verwijderd mogen worden. Dit doe ik aan de hand van onderstaande query.
31
public List<String> filterList(List<String> wordList) { List<String> filteredList = new ArrayList<String>(); Cursor cursor = null; database.beginTransaction(); try{ for (String wordId : wordList) { String[] whereArgs = new String[]{wordId}; try { cursor = database.query( MySQLiteHelper.TABLE_PLAYLIST_DATA, allColumns, MySQLiteHelper.COLUMN_WORDID + "=?", whereArgs, null, null, null); if(cursor.getCount() == 1){ filteredList.add(wordId); } } catch (SQLException e) { } finally { cursor.close(); } } database.setTransactionSuccessful(); }finally{ database.endTransaction(); } return filteredList; } Codevoorbeeld 4.3.3c Filteren van woorden
De instellingen die men veranderd worden opgeslagen zodat de andere activiteiten deze kunnen oproepen. Hierover meer in het puntje “Opslaan van gegevens”. 4.3.4
TrainchineseListsActivity
Deze activiteit toont een scherm waar de gebruiker afspeellijsten van zijn Trainchinese account kan importeren. Om tot dit scherm te geraken moet men op de knop “Lists from my Trainchinese account” drukken. De gegevens van de gebruikers en hun afspeellijsten van Trainchinese staan op de server van Molatra. Dit betekent dat ik een connectie moet maken met deze server. Dit proces gebeurt in een aantal stappen. De achterliggende code leg ik niet uit om veiligheidsredenen. Inloggen: Na het drukken op de knop krijgt de gebruiker een invoer scherm te zien waarop hij kan aanmelden met zijn Trainchinese Account.
32
Figuur 4.3.4a Inloggen
Gegevens versturen: Vervolgens worden deze gegevens, via een http POST naar de server gestuurd. Controle van gegevens: De gegevens worden gecontroleerd, wanneer deze correct zijn stuurt de server een bestand met daarin de namen van de afspeellijsten van de gebruiker. Wanneer de gegevens fout zijn ingevoerd stuurt de server een gepaste melding.
Figuur 4.3.4b Foutmelding
Tonen van woordenlijsten: Als de gegevens correct zijn verwerk ik dit bestand zodat er een lijst kan getoond worden met de afspeellijsten van de gebruiker.
33
Figuur 4.3.4c Lijsten van Trainchinese account
Woorden aanvragen aan de server: Vervolgens wanneer de gebruiker een lijst selecteert, vraag ik aan de server welke woorden deze lijst bevat. Ook wordt er tijdens deze stap nog eens gecontroleerd of de gebruikersnaam en wachtwoord correct zijn. Lijst filteren met woorden die nog niet zijn gedownload: Uiteindelijk filter ik deze lijst zodat ik alleen een lijst overhoudt met woorden die nog niet in de database staan. Nadien wordt de bijhorende data gedownload en wordt de ListenersActivity getoond.
Figuur 4.3.4d Starten van een afspeellijst
4.3.5
Activity’s lifecycle
Terwijl de gebruiker woorden aan het trainen is moet hij/zij instaat zijn om andere applicaties te openen, dit terwijl de audio nog moet blijven spelen. Hetzelfde geldt voor
34
wanneer de gebruiker het scherm afzet. Om dit te implementeren is het nodig om de “Activity’s lifecycle” te begrijpen. Dit biedt niet alleen oplossingen voor mijn probleem maar ook problemen zoals: “Wat moet er gebeuren bij de overgang naar een andere activiteit?”, “Wat gebeurd er met een activiteit wanneer de applicatie plots stopt?”. Deze problemen moeten behandeld worden zodat de gebruiker geen foutmeldingen tegenkomt. Een activiteit bevat een aantal methoden die worden uitgevoerd wanneer de activiteit in een bepaalde status is.
Figuur 4.3.5 Activity’s lifecycle
In deze figuur ziet men welke methoden worden uitgevoerd tijdens het opstarten en afsluiten van je applicatie. Ik leg deze methoden uit aan de hand van de activiteiten die Chineselistener gebruikt. onCreate() Deze methode wordt uitgevoerd wanneer de applicatie voor het eerst wordt aangemaakt. Hierin moet men de essentiële onderdelen van de activiteit initialiseren. Het belangrijkste onderdeel dat men moet doen is de lay-out definiëren voor de activiteit. Dit doe je via de methode setContentView().
35
Wanneer een activiteit wordt gestart door een andere activiteit is de kans groot dat er gegevens mee worden verstuurd. In deze methode worden deze gegevens ook opgenomen en verwerkt. De ListenersActivity wordt altijd geopend vanuit een andere activiteit, deze activiteiten geven een lijst met woorden mee zodat de activiteit weet welke woorden er moeten worden afgespeeld. Deze methode wordt steeds gevolgd door onStart(). @Override public void onCreate(Bundle savedInstanceState) { Log.v("Class ListenerActivity[onCreate()]", "Creating ListenerActivity"); super.onCreate(savedInstanceState); setContentView(R.layout.main); setVolumeControlStream(AudioManager.STREAM_MUSIC); prefs = PreferenceManager.getDefaultSharedPreferences(this); // findViewById getViewByIds(); // receive intent getIntentElements(); // preferences getPreferences(); // title bar setTitle("Now playing: " + playlistName); } Codevoorbeeld 4.3.5a onCreate() methode
onStart() Juist voordat de activiteit zichtbaar wordt voor de gebruiker wordt deze methode uitgevoerd. onResume() Deze methode wordt uitgevoerd wanneer de activiteit aan de gebruiker wordt getoond. onPause() De methode wordt opgeroepen wanneer het systeem een andere activiteit gaat starten. Hierin worden gegevens opgeslagen en processen gestopt zodat de CPU niet onnodig wordt gebruikt. In de ListenersActivity is dit een belangrijke methode omdat hier wordt bepaald of het geluid moet stoppen met afspelen of niet.
36
@Override public void onPause() { Log.v("Class ListenerActivity[onPause()]", "Pausing ListenerActivity"); if (this.isFinishing()) { Log.v("Class ListenerActivity[onPause()]", "Pressed Back button"); saveSettings(); pauseAndReleaseAudio(); } else { Log.v("Class ListenerActivity[onPause()]", "Pressed Home button"); } super.onPause(); } Codevoorbeeld 4.3.5b onPause() methode
onStop() Wanneer de activiteit niet meer zichtbaar is voor de gebruiker wordt deze methode opgeroepen. Dit kan gebeuren omdat er een andere activiteit is hervat of wanneer de activiteit is vernietigd. Deze methode wordt gevolgd door de methode onRestart() als het de activiteit nog terug wordt getoond of door onDestroy() als de activiteit verdwijnt. Wanneer de gebruiker een lijst selecteert die hij wil leren, moeten deze bestanden gedownload worden. Omdat sommige lijsten groot kunnen zijn, download het programma deze bestanden in kleinere delen. Een voordeel hiervan is wanneer het internet uitvalt of er een ander probleem voorvalt, de gebruiker het hele bestand niet terug hoeft te downloaden. Om dit goed te kunnen laten functioneren, moet ik in deze methode het deel opslaan wat de gebruiker het laatst heeft gedownload.
37
@Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.v("MenuActivity onStop()", "stop"); if (!homeButton) { if (downloading) { boolean delete = true; if (hsk5counter > 1) { saveItems(hsk5part, hsk5counter + 1, true); hsk5counter = 2; hsk5part = 1; delete = false; } if (hsk6counter > 1) { saveItems(hsk6part, hsk6counter + 1, true); hsk6counter = 5; hsk6part = 1; delete = false; } if (delete) { Log.v("MenuActivity onStop()", "deleting playlist"); // delete playlist table deletePlaylist(playlistId); } } } } Codevoorbeeld 4.3.5c onStop() methode
onRestart() Als de applicatie opnieuw wordt gestart word deze methode opgeroepen. onDestroy() Voor dat de applicatie wordt vernietigd word deze methode opgeroepen. Dit is de laatste methode dat de activiteit zal uitvoeren. 4.3.6
Intent
Om een nieuwe activiteit te starten, gebruik je in Android een object van de klasse Intent. Een nieuwe activiteit kan een activiteit zijn binnen de applicatie maar het kan ook bijvoorbeeld een andere applicatie zijn zoals Notepad. Men kan aan deze intent ook data binden. In de MenuActivity gebruik ik een intent om ListenersActivity te openen. In het menu scherm wordt data opgevraagd, en het luisterscherm heeft data nodig om te functioneren. Hiervoor moet ik die welbepaalde data binden aan een intent zodat het luisterscherm deze data eruit kan pakken. Versturen (MenuActivity): Via het menuscherm start men het luisterscherm, de data die het luisterscherm nodig heeft zijn: de lijst met woorden, de naam van de afspeellijst en het bijhorende ID.
38
Intent listenerIntent = new Intent(); listenerIntent .setClass(context, ListenerActivity.class); listenerIntent.putExtra("wordsArray", output); listenerIntent.putExtra("playlistName", playlistName); listenerIntent.putExtra("playlistId", playlistId); startActivityForResult(listenerIntent, 0); Codevoorbeeld 4.3.6a Starten van een nieuwe intent
Ontvangen (ListenersActivity): De extra data die bij de intent hoort moeten we opvangen. De onderstaande code zorgt hiervoor.
private void getIntentElements() { // receive intents playlistId = getIntent().getLongExtra("playlistId", -1); playlistName = getIntent().getStringExtra("playlistName"); wordListArrayP = getIntent().getParcelableArrayExtra("wordsArray");
// from parcel to array if (wordListArrayP != null) { wordListArray = new Word[wordListArrayP.length]; for (int i = 0; i <= wordListArrayP.length - 1; i++) { wordListArray[i] = (Word) wordListArrayP[i]; } setViewPager(); } else { Dialogs.progressWithBackgroundTask(this, "loading words", new OnTaskListener() { public Boolean taskInBackground( Context context, ProgressDialog dialog) { getWords(); return true; } public void finishOnMain( Context context, Boolean result) { // viewpager setViewPager(); }
}).show(); } } Codevoorbeeld 4.3.6b Ontvangen van een intent
4.4
Opslaan van gegevens
Chineselistener gebruikt een heleboel gegevens die op een efficiënte manier opgeslagen moeten worden. Android biedt verschillende opties voor gegevens op te slaan. Welke optie men gebruikt hangt af van de specifieke behoeften, zoals moeten de gegevens privé blijven voor je applicatie of toegankelijk zijn voor andere toepassingen. In dit hoofdstuk bespreek ik de twee methodes die ik het meest heb gebruikt voor het opslaan van gegevens.
39
4.4.1
SQLite
Met SQLite kan men gestructureerde gegevens opslaan in een privé database. SQLite is beschikbaar op elk apparaat en Android biedt volledige ondersteuning voor deze database. Gegevens die men opslaat in de SQLite database zijn toegankelijk voor alle activiteiten binnenin de applicatie. Wanneer men SQLite gebruikt voor Android moet men niets doen van installatie of beheer, men moet alleen maar SQL instructies definiëren voor het aanmaken en updaten van de database. Na het ingeven van deze instructies wordt de database automatisch gecreëerd door het Android platform. Voor het aanmaken van de database heb ik een aantal klassen moeten maken. MySQLiteHelper.java Voor het aanmaken en upgraden van een database in Android gebruikt men meestal een subklasse die gebruikt maakt van de klasse SQLiteOpenHelper. In de constructor van deze klasse roep je de super() methode op met daarin de naam en de versie van de database. Dit wil zeggen dat men de constructor van de superklasse gebruikt(SQLiteOpenHelper).
public MySQLiteHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } Codevoorbeeld 4.4.1a MySQLiteHelper
In deze klasse moet men ook 2 methodes overschrijven namelijk onCreate() en onUpdate(). De methode onCreate() wordt opgeroepen wanneer de database nog niet aangemaakt is. Beide methodes hebben als parameter een object van de klasse SQLitedatabase nodig. SQLiteDatabase is de basisklasse voor het werken met een SQLite database in Android. Het biedt methoden aan om de database te openen, querys uit te voeren en de database te sluiten. @Override public void onCreate(SQLiteDatabase database) { Log.i("Class MySQLiteHelper[onCreate()]", "creating database"); database.execSQL(DATABASE_CREATE_WORDS); database.execSQL(DATABASE_CREATE_INDEX); database.execSQL(DATABASE_CREATE_PLAYLIST); database.execSQL(DATABASE_CREATE_PLAYLISTDATA); } Codevoorbeeld 4.4.1b Creëren van database
In deze methode wordt de database aangemaakt, dus ook de tabellen die Chineselistener nodig heeft. De tabellen maak ik door voor elke tabel een query uit te voeren op de basisklasse SQLiteDatabase. Een voorbeeld de query voor het aanmaken van de tabel “playlist” zie je in onderstaand stukje code.
40
private static + + + + +
final String DATABASE_CREATE_PLAYLIST = "create table " TABLE_PLAYLIST + "( " COLUMN_ID + " integer primary key autoincrement, " COLUMN_PLAYLIST_NAME + " text not null , " COLUMN_MISSING_WORDS + " integer , " COLUMN_SIZE + " integer );";
Codevoorbeeld 4.4.1c Creëren van de playlist tabel
De database die aangemaakt is kan men oproepen door de methode getWritableDatabase() uit te voeren op deze subklasse. Playlist.java Het is een goed idee om voor elke tabel een klasse te maken. Objecten van deze klasse bevatten dan de gegevens die we later in de database kunnen opslaan en ook weergeven in de applicatie. Voor de tabel “playlist” maken we dan een klasse “playlist”. Deze klasse bevat alle attributen die we ook in de tabel gebruiken met de bijhorende getters en setters voor de data op te vragen en of te wijzigen. De constructor van deze klasse ziet er als volgt uit:
public Playlist(long id, String name, int missingWords, int size, int complete) { super(); this.id = id; this.name = name; this.missingWords = missingWords; this.size = size; this.complete = complete; } Codevoorbeeld 4.4.1d Playlist klasse
PlaylistDatasource.java Als laatste stap hebben we nog een object nodig dat connectie maakt met de database en die men kan gebruiken om query’s op de tabel uit te voeren. Dit object wordt het Data Access Object genoemd. Voor het beheren van de tabel “playlist” maken we een “PlaylistDatasource” klasse aan. In deze klasse staan al de methodes die de applicatie nodig heeft om data van deze tabel te halen of er in te schrijven.
41
public List getAllPlaylists() { List playlists = new ArrayList(); Cursor cursor = database.query(MySQLiteHelper.TABLE_PLAYLIST, allColumns, null, null, null, null, MySQLiteHelper.COLUMN_PLAYLIST_NAME); if (cursor != null && cursor.moveToFirst()) { while (!cursor.isAfterLast()) { Playlist playlist = cursorToPlaylist(cursor); playlists.add(playlist); cursor.moveToNext(); } } cursor.close(); return playlists; } Codevoorbeeld 4.4.1e Afspeellijsten van database halen
Met de bovenstaande methode in de klasse “PlaylistDatasource” haalt men al de afspeellijsten van de database en steekt men deze in een ArrayList. Zoals je kan zien geeft een query een object terug van het type Cursor. Dit object bevat de “rijen” van de query. Men kan de rijen hierna doorlopen met een while lus. Een belangrijk voordeel van deze methode is dat het systeem hierdoor niet al de gegevens in één keer moet laden. De gegevens van deze cursor moeten we opslaan in het object playlist van de klasse “Playlist”.
private Playlist cursorToPlaylist(Cursor cursor) { Playlist playlist = new Playlist(); playlist.setId(cursor.getLong(0)); playlist.setName(cursor.getString(1)); playlist.setMissingWords(cursor.getInt(2)); playlist.setSize(cursor.getInt(3)); Log.v("cursor", "" + cursor.getInt(3)); return playlist; } Codevoorbeeld 4.4.1f Playlist opvullen
Interface Na het maken van deze klassen kan men op een makkelijke manier de data uit de database halen en deze laten tonen aan de gebruiker. In het menu scherm toon ik een lijst met de afspeellijsten aan de gebruiker via onderstaande code.
42
public void getCustomPlaylists() { playlists = null; playlistDatasource.open(); playlists = playlistDatasource.getAllCustomPlaylists(); playlistDatasource.close(); adap = new EfficientAdapter(this); adap.setPlaylists(playlists); setListAdapter(adap); adap.notifyDataSetChanged(); } Codevoorbeeld 4.4.1g Afspeellijsten weergeven in een listview
4.4.2
Shared Preferences
Wanneer de gebruiker de applicatie naar zijn zinnen geconfigureerd heeft is het handig dat hij/zij dit niet altijd opnieuw moet instellen. Android ondersteunt het gebruik van instellingen. Via de preferencesManager kunnen we instellingen opslaan en ook later terug opvragen.
private void getPreferences() { this.timeBetweenTranslation = prefs.getInt("timeBetweenTranslation", 3000); selectedLanguageTimes = prefs.getInt("timesEnglish", 1); chineseLanguageTimes = prefs.getInt("timesChinese", 1); language = prefs.getBoolean("orderAudio", true); getVolume(); } Codevoorbeeld 4.4.2.1 Instellingen opvragen
Bij het opstarten van het luisterscherm haal ik de voorkeuren op van de gebruiker. Ik haal onder andere de tijd van de pauze op voor een vertaling begint. Deze kan men instellen via het instellingen menu. Wanneer de gebruiker nog niets heeft veranderd wordt er een standaard waarde van 3000mms ingesteld. Voor het maken of wijzigen van instellingen moet je de edit() methode oproepen op het SharedPreferences object. Om deze wijzingen toe te passen moet je de commit() methode toepassen.
43
private void saveSettings() { Log.i("Class ListenerActivity[saveSettings()]", "saving settings!"); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(this); Editor e = prefs.edit(); e.putBoolean("orderAudio", language); e.putInt("timesEnglish", selectedLanguageTimes); e.putInt("timesChinese", chineseLanguageTimes); e.commit(); } Codevoorbeeld 4.4.2.2 Instellingen opslaan
Bovenstaande code laat zien hoe ik de instellingen opslaan die de gebruiker heeft ingegeven wanneer hij woorden aan het trainen is. Ik sla in dit stukje code de volgorde van audio op en hoeveel keer dit wordt gesproken.
4.5
Werken met audio bestanden
Een groot deel van de applicatie bestaat uit het gebruik van audio bestanden. Hoe deze worden gedownload en afgespeeld vertel ik in dit hoofdstuk. Het proces bestaat uit het downloaden van een groot bestand, verdelen in kleinere audio bestanden, deze opslaan en daarna afspelen. Beveiliging is een belangrijk punt voor Molatra. Omdat ze een eigen gemaakte woordenboek gebruiken is het belangrijk dat deze gegevens niet zomaar kunnen worden opgepikt. Er steekt namelijk heel veel werk in om van elk woord een uitspraak op te nemen en de bijhorende betekenis op te zoeken in het Engels, Spaans en Russisch. De gegevens die ik ontvang van de server zijn geëncrypteerd, de applicatie moet ervoor zorgen dat deze leesbaar worden en geëncrypteerd terug worden opgeslagen. De encryptie komt niet aan bod om veiligheidsredenen. 4.5.1
Downloaden
Bij de installatie van mijn applicatie worden er geen bestanden meegegeven zodat het installatie bestand niet te groot wordt. Dit wil zeggen wanneer de gebruiker een lijst selecteert dat hij wil oefenen, de audio en de data eerst moet downloaden. Na het downloaden wordt de data op de gsm opgeslagen en hoeft hij dit niet meer opnieuw te doen.
44
Figuur.4.5.1 Downloaden van een afspeellijst
De bestanden zijn gelokaliseerd op de website. Wanneer we naar de juiste link surfen kan men de bestanden opvragen via een POST request. Ik moet ervoor zorgen dat mijn applicatie kan connecteren naar deze site en een POST request kan uitvoeren met de juiste parameters. Onderstaande code zorgt ervoor:
HttpClient client = new DefaultHttpClient(); HttpConnectionParams .setConnectionTimeout(client.getParams(), 60 * 2000); HttpPost post = new HttpPost( "http://www.trainchinese.com/v1/audioTrainer/getAudio.php"); MultipartEntity reqEntity = new MultipartEntity( HttpMultipartMode.BROWSER_COMPATIBLE); try { if (selectHSK) { reqEntity.addPart("nHsk", new StringBody (nameOfList, charset)); } else { reqEntity.addPart("w", new StringBody( wordIdsThatNeedToBeSendToServer, charset)); } post.setEntity(reqEntity); HttpResponse response = null; response = client.execute(post); Codevoorbeeld 4.5.1.1 Aanmaken van een HTTP cliënt
We maken gebruik van de Httpclient klasse. Deze cliënt maakt het mogelijk om een POST request uit te voeren met parameters. Het resultaat hiervan is een HttpResponse. Het eigenlijke bestand vragen we op via getEntity en stoppen we in een object van de klasse HttpEntity.
45
Nu dat we beschikken over het data bestand moeten we dit nog kunnen inlezen. Om dit te doen hebben we een inputstream nodig. Een inputstream heeft als parameter data nodig, de data kunnen we opvragen via getContent() op het object httpEntity. Na deze procedure moeten we dit bestand nog opslaan. Dit doen we doormiddel van een outputstream.
input = new BufferedInputStream(resEntity.getContent(), 8192); File mp3FileC = new File(mp3DirCache, "data"); Log.i("MP3", "-- saving DATA FILE to " + mp3FileC.getAbsolutePath()); FileOutputStream fos = new FileOutputStream(mp3FileC, false); byte[] data = new byte[1024]; long total = 0; int count = 0; while ((count = input.read(data)) != -1) { total += count; int percentage = ((int) total * 100 / (int) responseLength); Log.i("MP3", "Downloaded " + count + " bytes (" + percentage + "%)"); // TODO: Progress is known here // ((int)total*100/(int)responseLength if (listener != null) listener.downloadProgress(percentage); fos.write(data, 0, count); } fos.flush(); fos.close(); Log.i("MP3", "-- audio downloaded"); Codevoorbeeld 4.5.1.2 Data opslaan
4.5.2
Splitsen en opslaan
Na het downloaden van dit groot bestand moeten we dit opdelen zodat we voor elk woord een apart geluidsfragment hebben. De woorden die dit bestand bevatten heb ik in de vorige stap al in een Arraylist gestopt. De objecten die hierin zitten zijn van de klasse Word. De klasse Word ziet er als volgt uit:
public Word(String wordId, String simplifiedChinese, String traditionalChinese, String pinyin, String englishType, String english, String spanishType, String spanish, String russianType, String russian, int offsetChinese, int lengthChinese, int offsetEnglish, int lengthEnglish, int offsetChineseEnc, int offsetEnglishEnc, int range, int count, int played, int missing, String filename) Codevoorbeeld 4.5.2.1 Klasse Word
Deze klasse heeft een aantal attributen die een belangrijke rol spelen in dit proces. De belangrijkste attributen zijn het wordId, de offset en de length. De offset vertelt ons waar het geluid van dit woord ergens bevind in het grote bestand. De length vertelt ons hoeveel bytes dit geluid in beslag neemt en het wordId dient als titel van het bestand. Met deze drie attributen kan ik het geluid uit dit grote bestand nemen en opslaan onder een zinvolle naam.
46
FileInputStream stream = new FileInputStream( mp3FileDownloaded); BufferedInputStream bis = new BufferedInputStream(stream, 8192); DataInputStream bytes = new DataInputStream(bis); FileOutputStream fos; byte[] dataBuffer; bytes.skip(w.getOffsetChinese() + offsetFirstFile); // To read bytes into an array dataBuffer = new byte[w.getLengthChinese()]; bytes.read(dataBuffer); // To write the bytes to a file File mp3FileC = new File(mp3DirChinese, w.getWordId() + ".mp3"); Log.i("MP3", "-- saving Chinese MP3 to " + mp3FileC.getAbsolutePath()); fos = new FileOutputStream(mp3FileC, false); fos.write(dataBuffer); size += mp3FileC.length(); fos.close(); stream.close(); bis.close(); bytes.close(); Codevoorbeeld 4.5.2.2 Data opsplitsen in kleinere delen
Voor het splitsen van bestanden heb je twee soorten streams nodig, namelijk een inputstream voor het lezen en een outputstream voor het schrijven van bestanden. De eerste stap in dit proces is het omzetten van de stream naar een dataInputStream, zodat we met de bytes van dit bestand kunnen werken. Vervolgens worden de bytes van het geluidsbestand in een array gestopt door middel van de offset en de lengte van het woord. Deze bytes kunnen we nu gebruiken om een nieuw mp3 bestand te schrijven met behulp van de outputStream. Dit doen we aan de hand van de write() methode. Deze stappen worden herhaald voor elk woord in de array list. In de laatste stap verwijder ik nog het grote bestand omdat dit niet meer wordt gebruikt.
// delete boolean deleted = mp3FileDownloaded.delete(); if (deleted) { Log.i("MP3", "-- big file deleted"); } Codevoorbeeld 4.5.2.3 Data verwijderen
4.5.3
Afspelen
Voor het afspelen van een audiobestand gebruik ik een object van de klasse Mediaplayer. Omdat ik ervoor gezorgd heb dat de bestandsnaam van de geluiden
47
overeenkomen met de id-nummers van de woorden weet ik welk geluid er bij welk woord hoort. Het afspelen van de woorden gebeurt in de ListenersActivity. De woorden van de afspeellijst die de gebruiker heeft geselecteerd worden in een array object gestopt. Deze array bevat dus objecten van de klasse Word. Wanneer er op de afspeelknop wordt gedrukt, word de audio geladen en daarna afgespeeld. Dit doe ik met de methodes loadAudioFile() en playAudio(). In de methode loadAudioFile() geven we als parameter het woord mee dat zichtbaar is voor de gebruiker. Als eerste stap moet ik het juiste geluids bestand initialiseren dat bij dit woord hoort. Dit doe ik aan de hand van het volgend stukje code: boolean sdCard = prefs.getBoolean("SDCard", false); String dir = ""; if (sdCard) { File sdc = Environment.getExternalStorageDirectory(); dir = sdc.getAbsolutePath(); } else { try { dir = getPackageManager().getPackageInfo( "com.molatra.chineselistener", 0) .applicationInfo.dataDir; } catch (NameNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } File mp3Dir = new File(dir + "/chineselistener/" + mp3DirLanguage); File audioWord = new File(mp3Dir, word.getWordId() + ".mp3"); Log.v("loadAudioFile(Word word)", "Loading audio: " + audioWord.getAbsolutePath());
Codevoorbeeld 4.5.3.1 Opslag locatie bepalen
Aangezien de gebruiker kan instellen of de geluiden opgeslagen worden in het interne of externe geheugen moeten we dit eerst opvragen. De eerste stap van deze code is dus het bepalen van de map waarin de audio bestanden zijn opgeslagen. Wanneer we de map kennen wordt het juiste audiobestand in het Object File gezet door middel van het ID van het huidige woord en de extensie “.mp3”. Nu we het juiste geluidsbestand hebben, moeten we nog een manier hebben om dit te kunnen afspelen. Hiervoor stelt Android een klasse MediaPlayer beschikbaar. Met dit object kunnen we geluidsbestanden afspelen, pauzeren en stoppen. Dit object heeft een aantal parameters nodig om te kunnen functioneren. Omdat ik een extra parameter nodig heb dat niet standaard in dit object zit, heb ik een extra klasse Audio aangemaakt. Deze klasse heeft dezelfde parameters nodig als de MediaPlayer klasse met alleen het verschil frequency. Frequency bepaald hoeveel keer het geluid wordt afgespeeld. De klasse ziet er als volgt uit:
48
public Audio(FileDescriptor fd, int frequency, float volume, int offset, int length) { this.frequency = frequency; this.volume = volume; this.fd = fd; this.offset = offset; this.length = length; loadAudio(); } Codevoorbeeld 4.5.3.2 Klasse Audio
In de loadAudio() methode maken we dan het Mediaplayer object aan. Dit object heeft een datasource nodig, de startbyte waar het moet beginnen(offset) en de lengte van de bytes die het moet afspelen(length). De datasource is het mp3 bestand.
private void loadAudio() { // TODO Auto-generated method stub try { Log.i("Class Audio[loadAudio()]", "Loading audio" + "(setting datasource,volume,prepare)"); mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(fd, offset, length); Log.i("Class Audio[loadAudio()]", "Setting volume [" + volume + "]"); mediaPlayer.setVolume(volume, volume); mediaPlayer.prepare(); isPrepared = true; mediaPlayer.setOnCompletionListener(this); } catch (Exception ex) { throw new RuntimeException("Couldn't load audio!"); } } Codevoorbeeld 4.5.3.3 Gebruik van mediaplayer
Wanneer het geluidsbestand is geladen voeren we de methode playAudio() uit. Deze methode zorgt ervoor dat het mediaplayer object wordt afgespeeld. Men kan dit ook pauzeren door de methode pause() uit te voeren.
private void playAudio(){ if (audio != null) { audio.playAudio(); } } Codevoorbeeld 4.5.3.4 Afspelen van geluiden
4.6
More en Less functie
De feature om woorden meer of minder op het scherm te laten tonen vereiste een beetje denkwerk. De manier waarop de woorden afspelen gebeurd op een random manier maar wanneer de gebruiker op bijvoorbeeld more heeft geklikt, moet dit woord meer keer voorkomen dan de andere woorden. Hiervoor heb ik een algoritme moeten samen stellen. 4.6.1
Algoritme
Het algoritme leg ik uit aan de hand van mijn tabel "words".
49
Figuur 4.6.1.1a Tabel words
Voor het algoritme heb ik 2 nieuwe kolommen aangemaakt namelijk range en count. Wanneer de lijst nog niet is afgespeeld zijn deze waarden respectievelijk 10 en 5. Als men nu op de knop more of less drukt zal de waarde van count met 1 vermeerderen of verminderen. De waarde van range veranderd met een dynamisch getal afhankelijk van de waarde van count. Dit getal is groter wanneer de count waarde dichter bij 10 ligt en kleiner wanneer de waarde dichter bij 1 ligt. Dit wil zeggen dat we geen lineaire groei bekomen maar een exponentiële groei. Wanneer de gebruiker nu op de knop more of less drukt heeft het een beter en sneller effect.
Figuur 4.6.1.1b Verschil tussen exponentiële groei en lineaire groei
Via de waarde range kunnen we ervoor zorgen dat de woorden met een hogere count vaker voorkomen. De berekening gaat als volgt: • • •
Som bepalen van de totale range; Genereren van een random nummer beginnend van 0 tot aan de som van de totale range; Het wordId zoeken waar het nummer tot toe behoort.
Het wordId dat men nu bekomt zal het volgende woord zijn dat verschijnt. 4.6.2
Implementatie
Bij de implementatie van dit algoritme moet er voor gezorgd worden wanneer men op de knop more of less drukt, dat de waarde van de count verhoogd/verminderd word. De range wordt automatisch aangepast aan deze waarde.
50
case R.id.ButtonMore: if (currentWord.getCount() < 10 && currentWord.getCount() >= 1) { currentWord.setCount(currentWord.getCount() + 1); } progressBar.invalidate(); progressBar.setProgress(currentWord.getCount()); wordDatasource.open(); wordDatasource.updateWordRange(currentWord); wordDatasource.close(); return; Codevoorbeeld 4.6.2a Frequentie verhogen
Nadat een woord is afgespeeld gebeurd de berekening welk woord als volgende wordt getoond. int randomNumber = findIndex(generateRandomNumber()); Word setWord = wordListArray[randomNumber]; Codevoorbeeld 4.6.2b Bepaling van het volgende woord
Eerst wordt er een random nummer gegenereerd, en via dit nummer wordt de wordId gezocht in de lijst van woorden. De methodes kan je hieronder zien.
51
public int generateRandomNumber() { sumOfTotalRange(); Random randomGenerator = new Random(); return randomGenerator.nextInt(sumOfTotalRange); } public void sumOfTotalRange() { sumOfTotalRange = 0; for (Word w : wordListArray) { if (w != null) { sumOfTotalRange += w.getRange(); } } } public int findIndex(int number) { int index = -1; int cumalative = 0; for (int i = 0; i <= wordListArray.length; i++) { cumalative += wordListArray[i].getRange(); if (number <= cumalative) { return i; } } return index; } Codevoorbeeld 4.6.2c Implementatie van het algoritme
4.7
AndroidManifest
Elke applicatie heeft een AndroidManifest bestand nodig om te kunnen werken. Dit bestand bevat essentiële informatie over de applicatie. Het systeem heeft deze nodig om de applicatie uit te voeren. In het manifest bestand declareert men volgende gegevens: Uses-permission: In het uses-permission element kan men de machtigingen instellen die de applicatie nodig heeft om bepaalde code uit te voeren. Chineselistener heeft een aantal machtigingen nodig om correct te kunnen functioneren, zoals het connecteren met het internet.
<uses-permission <uses-permission <uses-permission <uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> android:name="android.permission.WAKE_LOCK" /> android:name="android.permission.INTERNET" /> android:name="android.permission.READ_PHONE_STATE" /> android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Codevoorbeeld 4.7a uses-permission
Manifest element: Het manifest element bevat een aantal attributen die ingevuld moeten worden. Het package attribuut definieert de basis package waarin de objecten zitten die worden
52
gebruikt in dit bestand. Android verplicht dat elke applicatie zijn eigen unieke package naam heeft. De versiecode en versienaam bepalen aan welke versie de applicatie momenteel zit. De versienaam is wat de gebruiker ziet. De versiecode wordt gebruikt door de Android market, wanneer dit nummer anders is als het nummer in de vorige applicatie zal het een update voeren bij de al bestaande installaties.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.molatra.chineselistener" android:versionCode="1" android:versionName="1.0" > Codevoorbeeld 4.7b Manifest element
Uses-sdk: Dit deel van het manifest bestand bepaalt de minimum sdk versie die nodig is om de applicatie uit te voeren. Wanneer deze is ingesteld op bijvoorbeeld sdk versie 10, kan men deze niet installeren op oudere versies.
<uses-sdk android:minSdkVersion="5" android:targetSdkVersion="11" /> Codevoorbeeld 4.7c Uses-sdk
Application: Dit element bevat attributen en sub elementen die algemene informatie geven aan de applicatie. Men kan onder andere het icoon instellen dat bij de applicatie hoort.
Codevoorbeeld 4.7d Application
In dit element declareren we ook de activiteiten die de applicatie gebruikt. Men kan aan bepaalde activiteiten extra instellingen geven. Zeker één activiteit moet de waarde krijgen van hoofdactiviteit. Hiermee weet het systeem dat deze activiteit eerst moet worden weergegeven bij het opstarten van de applicatie. Standaard declareren we ook het label dat bij de activiteit hoort. Dit label wordt getoond in de titelbalk bij het opstarten van de activiteit. Ik heb mijn activiteiten ook nog een extra instelling meegeven, dit zorgt ervoor dat bij veranderen van oriëntatie er een methode wordt opgeroepen in die activiteit.
53
Codevoorbeeld 4.7e Aanmaken van activiteiten
4.8
Debuggen met Eclipse
Doorheen het project ben ik veel bugs tegengekomen. Hiervoor is het nodig om een goed inzicht te krijgen over de foutopsporing van je applicatie. In dit hoofdstuk leg ik uit welke technieken ik hiervoor heb gebruikt. 4.8.1
Logcat
Logcat wordt gebruikt om informatie uit te wisselen vanuit de toepassing op uw apparaat naar de ontwikkelomgeving. Logcat verzamelt systeem berichten, zoals fout meldingen en gewone meldingen maar men kan ook zelf berichten creëren. Om dit te kunnen gebruiken moet men de klasse android.util.log importeren. Wanneer men nu een bericht wilt laten zien op de display moet men de klasse Log oproepen. De berichten zijn onderverdeeld in 7 verschillende soorten: • • • • •
Log.v – Verbose Log.d – Debug Log.i – Info Log.w – Warning Log.e - Error
Bij het opsporen van fouten gebruikte ik gewoonlijk de Debug Log, hiermee kan je de vooruitgang van de applicatie loggen. Ik heb ook veel gebruik gemaakt van Info, hiermee toon ik berichten in het uitvoer scherm wat er juist aan het gebeuren is. Deze info kan ook als commentaar dienen. Wanneer men deze logs wilt bekijken moet men, voor de toepassing wordt gestart, het Logcat venster openen. Aan de onderkant van het scherm ziet men de berichten verschijnen:
54
Figuur.4.8.1a Logcat
Men kan ook deze log berichten filteren. In onderstaande figuur heb ik een filter ingesteld zodat alleen de Info logs worden weergegeven. De onderstaande logs worden gemaakt tijdens het afspelen van woorden.
Figuur.4.8.1b Logcat met filter
4.8.2
Debug mode
Via Logcat kunnen we al veel te weten komen over wat er aan het gebeuren is. Soms is de fout te ingewikkeld om op te lossen en moeten we een andere methode gebruiken. Hiervoor kan men de applicatie opstarten via debug mode, hierin kunnen we de variabelen zien veranderen en kunnen we ook breakpoints in de code zetten. Je moet hiervoor wel het scherm “Debug perspective” openen.
55
Figuur.4.8.2 Debug mode
Wanneer je de applicatie opstart via Debug mode krijg je dit scherm te zien. In de rechter boven hoek kan men de waarde van elke variabel die wordt gebruikt in de activiteit bekijken. Onderaan het scherm worden de logs weergegeven en in het midden van het scherm zien we in welk stukje code de applicatie momenteel is.
Figuur 4.8.2b Navigatie knoppen
De gebruiker kan doorheen de breakpoints scrollen door op de groene knop te drukken, hij kan ook de debugger afsluiten door op de rode knop te drukken.
56
BESLUIT…. De afgelopen 13 weken heb ik tijdens mijn stage gewerkt aan de ontwikkeling van een gloednieuwe applicatie voor Android. Deze applicatie is een hulpmiddel bij het leren van Chinees. De gebruiker kan met Chineselistener de basiswoorden leren door behulp van ingebouwde woordenlijsten, of door zelf lijsten te creëren via Trainchinese Dictionary. De door mij ontwikkelde applicatie kan men als toevoeging gebruiken van de andere applicaties van Molatra maar het kan evengoed stand-alone gebruikt worden. Deze mobiele applicatie is momenteel in testfase. De vertrouwde gebruikers van Trainchinese krijgen de kans om deze applicatie te testen. Als alles goed verloopt, zal de applicatie binnenkort verkrijgbaar zijn op Google Play onder de naam Chineselistener. Er is momenteel veel vraag naar mobiele applicaties door de opkomst van smartphones en tablets. Hierdoor ben ik ontzettend blij dat Molatra mij de kans en de verantwoordelijkheid heeft gegeven om een applicatie vanaf nul te ontwikkelen. Deze ervaring heeft me nog meer interesse doen opwekken in het ontwikkelen van mobiele applicaties. Hierdoor zal de stap makkelijker te zetten zijn naar het maken van mijn eigen applicatie, wat ik altijd al heb gewild. Doordat ik mijn stage heb gelopen in het buitenland, namelijk China heb ik ook nog andere ervaringen opgedaan dan alleen op het vlak van programmeren. Molatra levert applicaties waarmee men Chinees kan leren, deze applicaties zijn ze ook aan het vertalen naar het Spaans, Frans en Russisch. Voor deze job hebben ze lokale inwoners nodig van die nationaliteit, hierdoor heb ik vele verschillende culturen leren kennen. Door de verschillende nationaliteiten was de voertaal in het bedrijf niet mijn vertrouwde Nederlands, maar Engels. Dit heeft ervoor gezorgd dat ik meer vertrouwd ben bij het spreken van een andere taal. Samengevat vond ik mijn stage zeer leerrijk en de ervaringen die ik hierbij heb opgedaan gaan zeker een invloed hebben op de keuzes die ik in mijn verdere leven zal maken.
57
LITERATUURLIJST Android. (2012). Opgeroepen op 2012, van Android developers: http://developer.android.com Stackoverflow. (2012). Opgeroepen op 2012, van Stackoverflow: http://www.stackoverflow.com Vogella. (2012). Opgeroepen op 2012, van Vogella: http://www.vogella.com