2014-06-03
Alma hittade en bugg i "Almas matteapp" igår. Det var när hon för första gången gjort klart övningen "Ettans gångertabell i ordning" som appen drog upp en errordialog och stängde ner Activity:n som kördes, vilken var den som visar upp resultatet av övningen. Alma utbrast "Men pappa!" med förebrående röst. Ooops. Vad skall man säga? Det är sådant som händer. Speciellt om man inte har en egen QA-avdelning utan sköter allt testandet själv ;)
Alma gjorde sedan två övningar till (ettans gångertabell utan ordning och sjuans gångertabell utan ordning), och efter varje gång kraschade Activity:n som skulle visa övningsresultatet. Illa, illa.
När jag senare på kvällen körde appen i debug-läge från Android Studio konstaterades det snabbt att det var en NPE i en metod som skapade texterna för hur lång tid användaren tog på sig för att lösa övningen. När det var första gången som användaren gjorde en övning var bönan som normalt sett håller föregående övningomgångars bästa tid null, vilket ledde till att Activity:n kraschade när bönan accessades. Inga problem att fixa, men varför hade jag då inte märkt av det själv när jag testat? Jag har ju gjort minst 20 övningar för första gången de senaste veckorna? Och varför har inte Alma och Alice märkt något när de använt appen?
Det visade sig att buggen bara uppkom för användare som har satt inställningen "Visa tidmätningar" till true. Den användaren som jag alltid loggar in med när jag testar har den inställnigen satt till false, så det var därför jag inte märkt av buggen. Gissar att det var samma sak för Alma och Alice. Tror att Alma precis ändrat den inställningen från false till true och det var därför beteendet förändrades för hennes användare nu. Ja, ja. Gött att vi hittade den nu i alla fall innan vi lagt upp appen på Play-butiken.
2014-06-09
I Almas matteapp finns det just nu två saker som är gjorda för att öka intresset för att fortsätta göra övningar: medaljer och utmärkelser. Medaljer får man när man gjort en viss övning ett visst antal gånger. Gör man en övning en gång får man en bronsmedalj, gör man den fem gånger får man en silvermedalj, tio gånger ger en guldmedalj och tjugo gånger en diamantmedalj.
Utmärkelser är ett sätt att belöna att man gör flera olika uppgifter. För vissa utmärkelser spelar det inte någon roll vilken kategori en uppgift tillhör, andra har krav på att uppgifterna man gör skall tillhöra vissa kategorier. För närvarande finns det fyra kategorier: addition, subtraktion, multiplikation och talkompisar. Jag har planer på att utöka listan med kategorier allteftersom jag lägger till fler övningar till appen.
Den första utmärkelsen har jag (till Almas stora förtret) kallat 'Tre ljusstakar'. För att få den behöver man ha fått tre bronsmedaljer. Vet förresten inte riktigt varför jag valde just namnet Tre ljusstakar. Tror att jag associerade brons med mästing och mässing med ljusstakar. Inte helt logiskt kanske, men vad tusan, något skall den ju heta.
Utmärkelser-konceptet är förresten hederligt snott från Project Euler. Vet att det där triggar mig att göra fler uppgifter så jag tänkte att det kanske kunde trigga appanvändarna på samma sätt.
Alma har varit bortrest i några dagar och när hon kom hem igår så berättade jag att jag implementerat en ny utmärkelse: PlusMinus. För att få den behöver man fått guldmedalj på en additionsövning och en subtraktionsövning. Hon frågade då om jag inte kunde göra en utmärkelse som hade med multiplikation att göra. Det lovade jag henne att göra.
Runt kl nio på kvällen plockar jag, mot bättre vetande eftersom jag var rätt trött och borde gå och lägga mig, fram datorn. Startar upp Android Studio som indikerar att det fanns en uppgradering (0.6.0) att installera, vilket jag då gjorde. Efter den obligatoriska omstarten försökte jag bygga projektet. Fel version av SDK-toolsetet. Skit också. Startar upp SDK-managern och uppdaterar toolsetet. Det tar en bra stund. Startar om Android Studio. Bygger om projektet. Fortfarande fel version av toolset:et. In i projektinställningarna. Hittar inställningen för toolset-version och ändrar till den nyligen uppdaterade. Bygger om projektet. Äntligen funkar det. Tidsåtgång på detta: ca 45 minuter. Min dator är snart fem år gammal så allt tar sin lilla stund...
Nu är jag rejält trött och borde verkligen gå och lägga mig. Tänker: 'om jag bara startar koda lite på den nya utmärkelsen så blir det lättare att komma igång imorgon'. Börjar med det jobbigaste: komma på vad utmärkelsen skall kräva och att lägga till namn och beskrivning på den i strings.xml. Detta är något som brukar ta en stund eftersom jag har dålig fantasi och därför svårt att komma på bra namn på saker och ting. Sitter och funderar en stund innan jag bestämmer mig för att utmärkelsen skall kräva att man fått en guldmedalj på tre multiplikationsövningar. Den blir rätt lätt att få eftersom det t.ex. finns två övningar på ettans gångertabell (med och utan ordning). Vad skall utmärkelsen heta då. Svåra frågor. Jag bestämmer mig för att bara ta något: 'Multiplikationstrippel' får det bli. Inte världens bästa namn, men om Alma protesterar alltför mycket så kan man alltid ändra i ett senare läge. Namnet visas bara för användaren. Det används inte internt och sparas inte i databasen, så man kan ändra i strings.xml utan att behöva ta några speciella hänsyn, vilket ju är skönt.
Nu var det bara resten kvar. Är nu ännu tröttare och funderar på om jag verkligen inte borde gå och lägga mig. Väljer dock att fortsätta. Bara lite till.
Alla utmärkelser har en egen klass. Klassen refereras från enumen Awards
. I den enum:en specas för varje enumerarat värde följande saker: värdets ID (1, 2, ...), namn (ref till strings.xml), beskrivning namn (ref till strings.xml) och klassliteralen för den klass som implementerar utmärkelsen.
Klassen som implementerar utmärkelsen skall implementera interfacet Award
. Detta interface definierar endast en metod: boolean requirementsFulfilled(MedalStatisticsDto)
. Denna metod skall returnera true om användaren erhållit utmärkelsen och false om så inte är fallet. Valet görs med hjälp av en böna av typen MedalStatisticsDto
som innehåller data om vilka medaljer som användaren fått.
Fördelen med att spara såpass mycket data i Awards
är att aktivitieten som visar upp listan med utmärkelser (erhållna samt icke än erhållna) blir extremt lätt att skriva. Det den i princip gör är att den loopar över alla värden i Awards
-enumen och i en ListView
visar upp en rad för varje värde. På en rad i ListView
:n skrivs namnet och beskrivningen på utmärkelsen i fråga. Det ritas också ut en ikon om användaren har erhållit utmärkelsen. Aktiviteten bestämmer om användaren erhållit utmärkelsen genom att skapa en instans av den klass som pekas ut av Awards
-enumen och anropa dess boolean requirementsFulfilled(MedalStatisticsDto)
metod. Jättesmidigt, om jag får säga det själv. Och det får jag ju eftersom det är min blogg ;)
I alla fall, när jag väl hade bestämt mig för vad utmärkelsen skulle heta så skapade jag en ny klass som ärvde från Award
och implementerade dess boolean requirementsFulfilled(MedalStatisticsDto)
-metod. Den blev 21 rader. Inklusive @Override
-annotering, tomrader och måsvingar (för left curly brace är ju den rätta placeringen är på raden under statmentet så varje par måsvingarökar ju på radantalet med två). Inte så illa.
Efter det var det bara att lägga till rad med ett nytt enum-värde i Awards
-enumen, testköra och checka in. Testkörningen tog lite tid eftersom jag var tvungen att få guld på tre multiplikationsövningar. Jag hade brons på alla sedan tidigare (testkör alltid alla nya övningar en gång) så jag var tvungen att göra 3 * 4 = 12 övningar var och en innehållande 11 uppgifter. Även om varje uppgift går snabbt (let's face it: ettans och tvåanstabell är inte så svåra) så tar 132 uppgifter sin lilla tid. Funkade som det skulle gjorde det i alla fall.
Kvällens facit: en ny utmärkelse implementerad. Relativ tidsåtgång per aktivitet: strul 50%, namnsättning: 10%, kodning: 15% och test: 25%. Som vanligt med andra ord.
2014-06-23
Har nu implementerat textuppgifter för addition i Almas matteapp. Trodde att det skulle bli ganska enkelt innan jag började. Märkte dock ganska snart efter det att jag börjat implementera att det inte var så lätt som jag trott.
Jag hade tänkt att skapa tio stycken parametriserade strängar för att representera uppgifterna. Strängarna skulle inledas med en beskrivning och avslutas med en fråga. Exempel: Alma har tre glaskulor och Alice har fyra glaskulor. Hur många glaskulor har Alma och Alice tillsammans?. Vidare var tanken att ha ett antal namn, säg tio stycken, och att appen skall slumpa fram vilka som skall användas vid varje körningstillfälle. Detta för att göra det lite roligare för barnen att göra uppgifterna. På samma sätt skall objekten ("glaskulor") och antalen som ingår i uppgifterna slumpas fram.
Android har ett bra stöd för parametriserbara strängar. I strings.xml
skapar man strängar som markörer av typen %1$s
på det ställen man vill parametrisera. 1:an i %1$s
står för att det är den första parametern och s:et för att det är ett strängvärde som skall sättas in. Det finns givetvis andra typparametrar än "s". Hade det stått ett d istället för ett s hade det betytt att ett heltal skulle stoppas in. Precis som i formatsträngen för C:s printf
När man vill använda en parametriserbar sträng från appens Java-kod använder man sig av varargs-metoden getString(int, Object...)
i klassen Resources
. En referens till Resources
kan man få från sin Activity
med hjälp av getApplicationContext().getResources()
. Exempel: för att hämta strängen med id "addition_text_one" från strings.xml
och binda "Alma" och "Alice" till de första parametrarna gör man följande innifrån en Activity
:getApplicationContext().getResources().getString(R.strings.addition_text_one, "Alma", "Alice")
Jag hade alltså tänkt att skapa tio sådana strängar, parametrisera alla namn, objekt och antal för att sedan använda dessa strängar för att skapa uppgifter. Det gick till slut, men var avsevärt jobbigare än jag trott. Vad var det då som gjorde det jobbigt?
- Objekten skall ibland stå i singular ("glaskula") och ibland i plural ("glaskulor").
- I singlular måste det bestämmas om det skall stå "en" eller "ett" framför objektet.
- I listan med namn finns det både pojk- och flicknamn. Det måste därför bestämmas om det skall skall stå "han" eller "hon" i frågorna.
- Bonusjobbighet: Min fantasi är inte i världsklass, så jag fick anstränga mig lite för att hitta på tio basuppgifter som inte var mer eller mindre identiska.
Hur löstes då problemen ovan? För närvarande är de lösta så här:
- I
strings.xml
finns det två arrayer med "saker": en med sakerna i singular och en i plural. På stället i koden som slumpar fram tal till frågorna kollas det om singularformen eller pluralformen skall användas baserat på om det framslumpade talet är ett eller inte. - Det finns i
strings.xml
ytterligare en array som innehåller med lika många items som det finns saker i arrayerna i 1). Denna array innehåller "en" eller "ett" beroende på om motsvarande substantivs genus. - Även detta löstes med en extra array i
strings.xml
. Den här arrayen har samma längd som arrayen med namn och innehåller "male" resp "female" beroende på om motsvarande namn är maskulint eller feminint. - Med ångest, vånda och uteblivet VM-tittande ;)
Är jag nöjd med lösningen? Så där. Det borde gå att hitta på något bättre. Samtidigt vill jag att strängliteralerna skall finnas i strings.xml
och inte i Java-kod. Hade varit trevligt att definera namn och singularformer av sakerna i strings.xml
och sedan anropa ett trevligt externt API för att bestämma reale/neutrum resp om ett namn är maskulint eller feminint. Fast å andra sidan vill jag inte att appen skall behöva komma åt nätverket...
Hade tänkt att gå vidare med att implementera textfrågor för subtraktion, men jag blev lite trött av strulet som var med de här uppgifterna så jag väntar nog ett tag med det. Skall kanske börja med uppgifter angående klockan istället. Vi får la se.
2014-12-02
Buggen fanns i den Activity
som visar upp resultatet av en avklarad övningsomgång. Problemet var att den från onCreate()
(via ett antal lager) sparade ner resultatet av övningsomgången i databasen.
Vad är problemet med det då? Så kan det väl fungera? Visst. Inget fel med det. Det är bara det att onCreate()
även anropas när man roterar devicet (ren svenska för apparaten som kör Android) så att den orienterar om sig från portrait till landscape eller tvärt om. Detta innebar att om man hade klarat en övningsomgång kunde man bara rotera devicet ett kvarts varv och vänta till den orienterat om sig. Sen hade appen registrerat ytterligare en lyckad övningsomgång. Ville man kunna man fortsätta rotera gång efter annan tills man erhållit den finaste medaljen.
Snacka om pinsam bugg. Tur att jag inte kommit så långt att jag laddat upp appen på Play-butiken än.
Var tvungen att fixa buggen snabbt så att jag inte skulle tappa all trovärdhet hos min äldsta dotter. Fick bli till att låsa skärmorienteringen till portrait. Får se till att fixa en bättre, mer permanent lösning så snart jag får tid. När det nu blir...
2017-02-20
I've finally managed to release the math app! It certainly took a while... I suppose I could have released it earlier, but there was always just one exercise or feature that I wanted to add to the app, so I never got around to do it. Until now...
Version 1.0 of the app contain more than different 125 exercises, which I'm very pleased with. I'll continue to add exercises whenever I feel that I find a good idea in one of the kids' math books :) Right now I'm thinking on implementing exercises about fractions. We'll see how that goes.
The app can be downloaded here.
It's free and contains no ads => I earn no money from it. But it would be fun if it would get many downloads :) And if it would be useful for someone else that my kids :)