How-to : Een simpele Game Loop

Mijn aPpLeZ-Game is gebaseerd op een eenvoudige tutorial, Droidz . In de komende posts zal ik uitleggen hoe het raamwerk van de game eruit ziet en hoe je zelf een simpele game kunt bouwen. Daarnaast zal ik ingaan op de problemen die ik tegenkwam bij het ontwikkelen van Applez. Uiteindelijk heb ik, voor Applez, 12 vragen gesteld aan de StackOverflow community. Als je in die community even zoekt op mijn naam, kun je vrij makkelijk de vragen over Applez vinden.

Goed. Een game. Hoe werkt dat eigenlijk in Android? Je moet bedenken dat er sprake is van een eenvoudige architectuur. De basis is eigenlijk : Controleer gebruikersinput > Controleer plaatsen en gebeurtenissen van objecten (Physics) > Verwerk data > Teken het scherm > Speel geluid af. Daarna begint de loop weer opnieuw. Dat alles gaat zo snel, dat je erop moet rekenen dat je bij een simpel spelletje, zoals Applez, al snel 50 keer per seconde het scherm kunt tekenen (50 Frames per Second). In de tekening bij deze post kun je de beschreven architectuur herkennen.

Hieronder geef ik de code voor een simpele game-loop. CopPa (jep, CopyPaste šŸ˜‰ ) maakt gebruik van een Background, een View, een Thread en een Activity. Als je deze op de juiste manier in je IDE hangt, heb je het begin van een game.Ā  Je moet de background (backgnd_coppaview.png) wel even maken in je favo tekenpakket en dan in de directory res\drawable-mdpi (voor medium-density schermen) zetten. Je kunt objecten die niet veranderen opnemen in de achtergrond. Dat kunnen dus ook best knoppen (buttons) zijn. Later, in de code, vang je de onTouchEvents af. Op dat moment zal je met code kijken in welk gebied de touch precies was. Als dat binnen de kaders van de button (op je achtergrond) was, dan kun je een routine uitvoeren.

Okido. Daar gaat ie met de eerste Activity :

package happyworx.nl.coppa;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

/**
 * @author k.koenen@happyworx.nl Gemaakt om een simpele game loop te
 *         demonstreren.
 */

public class CoppaActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Verzoek om het de titelbalk van het scherm uit te zetten
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		// Volledig scherm gebruiken
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		// De CoppaView class wordt de view die we gaan gebruiken
		// Als je advertenties aan je game wilt toevoegen,
		// zul je hier de trukendoos los moeten trekken.
		// Je maakt dan een new RelativeLayout en voegt
		// niet alleen de CoppaView, maar ook de AdView
		// daaraan toe.
		setContentView(new CoppaView(this));
	}
}

Zoals je ziet, wordt de ContentView gezet naar de CoppaView class. Dat is dan ook de volgende die we gaan bekijken;

package happyworx.nl.coppa;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;

public class CoppaView extends SurfaceView implements SurfaceHolder.Callback {

	// Een variabele voor de Thread (die de gameloop uitvoert)
	private MainThread thread;
	// En eentje voor de achtergrond van deze view
	private BackGndManager backGnd;

	// Public uitleesbare variabelen voor grootte van het scherm. De RectScreen
	// vullen we later met de juiste dimensies. Deze RectScreen is nodig in de
	// BackGndManager om ervoor te zorgen dat de achtergrond netjes het hele
	// scherm van de telefoon vult.
	public static Rect RectScreen = new Rect(0, 0, 0, 0);
	public int height;
	public int width;

	// Als de CoppaView class gemaakt wordt in een andere class, dan wordt eerst
	// de routine hieronder uitgevoerd. (dus ook bij de setContentView =
	// (new..))
	public CoppaView(Context context) {
		super(context);

		// Een surface wordt in een surfaceholder vastgehouden. Om events te
		// kunnen
		// vangen, moeten we een addCallback aan de SurfaceHolder toevoegen.
		getHolder().addCallback(this);

		// Even een paar dingen die we nodig hebben om een achtergrond voor deze
		// view te definieren. Ik heb een BackGndManager gemaakt, die binnen de
		// view de back-ground voor zn rekening neemt. We voeren de
		// BackGndManager een bitmap en de BackGndManager beschikt zelf ook over
		// een onDraw-routine, zodat we kleine wijzigingen daar kunnen laten
		// aanbrengen. Geen idee of dit de meest praktische routine is,
		// voorlopig hanteer ik hem even. Eerst de eigenschappen van het display
		// uitlezen en opslaan in de variabelen.

		Display display = ((WindowManager) getContext().getSystemService(
				Context.WINDOW_SERVICE)).getDefaultDisplay();
		width = display.getWidth();
		height = display.getHeight();
		RectScreen.set(0, 0, width, height);

		// Nu de background voor deze view definieren.
		backGnd = new BackGndManager(BitmapFactory.decodeResource(
				getResources(), R.drawable.backgnd_coppaview), 0, 0);

		// We definieren een thread die de GameLoop zal uitvoeren.
		// Door dit te doen, zal de code in public MainThread... (in de
		// Mainthread class)
		// dus direct worden uitgevoerd!
		thread = new MainThread(getHolder(), this);

		// We maken de CoppaView 'focussable' zodat events kunnen worden
		// afgehandeld
		setFocusable(true);

	}

	public void surfaceCreated(SurfaceHolder holder) {
		// Hier weten we zeker dat het surface is gecreeerd
		// En kunnen we dus de thread starten

		thread.setRunning(true);
		thread.start();
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// Hier kun je code toevoegen die wordt uitgevoerd als het Surface is
		// veranderd. Volgens mij valt hier ook onder; als het surface opnieuw
		// wordt opgebouwd doordat bijvoorbeeld de gebruiker de telefoon heeft
		// gedraaid (naar andere screen-orientation)
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		// En hier code voor als het surface niet meer bestaat (applicatie wordt
		// afgesloten of de Activity die het surface houdt wordt door het
		// systeem beeindigd.
	}

	// In de routine hieronder vangen we de touch-events af voor de
	// CoppaView-class

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			Toast.makeText(getContext(), "INGEDRUKT!", Toast.LENGTH_SHORT)
					.show();
		}

		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			Log.d("CoppaView", "It's a drag");
		}

		if (event.getAction() == MotionEvent.ACTION_UP) {
			Toast.makeText(getContext(), "LOSGELATEN!", Toast.LENGTH_SHORT)
					.show();

			if (event.getY() > height - 100) {
				// Voorbeeld : Als de touch wordt losgelaten in de onderste 100
				// pixels van het scherm kunnen we hier code uitvoeren
			}
		}
		return true;
	}

	// Als de geassocieerde MainThread een
	// this.coppaView.onDraw(MainThread.canvas); doet, Wordt onderstaande code
	// uitgevoerd
	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.BLACK);
		// Onderstaande regel voert dus de draw routine uit van de
		// backGndManager class
		backGnd.draw(canvas);
	}
}

Dan BackGndManager.java ;

package happyworx.nl.coppa;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

public class BackGndManager {

	private Bitmap bitmap;
	private Context context;
	public int width;
	public int height;
	public int x;
	public int y;
	public static Rect RectBackGnd = new Rect(0, 0, 0, 0);

	public BackGndManager(Bitmap bitmap, int x, int y) {

		this.bitmap = bitmap;
		width = bitmap.getWidth();
		height = bitmap.getHeight();
		this.x = x;
		this.y = y;
		this.RectBackGnd.set(0, 0, width, height);

	}

	public Bitmap getBitmap() {
		return bitmap;
	}

	public void setBitmap(Bitmap bitmap) {
		this.bitmap = bitmap;
	}

	public int getWidth() {
		return bitmap.getWidth();
	}

	public int getHeight() {
		return bitmap.getHeight();
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public void draw(Canvas canvas) {
		// Hier zie je hoe we de CoppaView RectScreen gebruiken om de bitmap
		// zodanig te vervormen, dat hij het hele scherm vult.
		canvas.drawBitmap(bitmap, RectBackGnd, CoppaView.RectScreen, null);
	}

}

Dan, het kloppend hart van de Game-Loop; de MainThread.
package happyworx.nl.coppa;

import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;

public class MainThread extends Thread {

	// Maak 2 variabelen voor de surfaceHolder en de View, die we later kunnen
	// gebruiken
	private SurfaceHolder surfaceHolder;
	private CoppaView coppaView;

	// Een aantal booleans geeft aan wat de status van de thread is
	public static boolean running;
	public static boolean paused = false;
	// Het canvas geeft een mogelijkheid om bitmaps te tekenen op het surface
	public static Canvas canvas;

	// Deze code wordt uitgevoerd op het moment dat de MainThread gecreerd wordt
	// (in de CoppaView, door de regel thread = new MainThread(getHolder(),
	// this);)

	public MainThread(SurfaceHolder surfaceHolder, CoppaView cview) {
		super();
		this.surfaceHolder = surfaceHolder;
		this.coppaView = cview;
	}

	// Met deze routine kunnen we de Thread vanuit een andere class stopzetten.
	public void setRunning(boolean running) {
		MainThread.running = running;
	}

	@Override
	public void run() {
		// Zo lang deze thread draait (running), moet de game worden geupdate en
		// getekend. Zie ook de grafische weergave van de game-architectuur
		// op http://happyworx.nl/blog
		while (running) {
			// Hier een stukje code dat we kunnen aanroepen door de boolean
			// paused op true te zetten
			// (bijvoorbeeld met een pauzeknop elders in de game)
			while (paused && running) {
				try {
					sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			MainThread.canvas = null;
			// try locking the canvas for exclusive pixel editing on the surface

			try {
				MainThread.canvas = this.surfaceHolder.lockCanvas();
				synchronized (surfaceHolder) {

					// Deze heb ik even ge-comment. In de routine
					// coppaView.update() zou je allerlei bewerkingen kunnen
					// doen die noodzakelijk zijn voor het updaten van de
					// objecten in de game. (is er iets opgegeten / afgeschoten
					// / verborgen / gebotst etc.)
					// this.coppaView.update();

					// Teken de view op het scherm (dit statement start dus de
					// routine onDraw in de View waar deze instantie van de
					// Thread bij hoort.

					this.coppaView.onDraw(MainThread.canvas);
				}

			} finally {
				if (MainThread.canvas != null) {
					surfaceHolder.unlockCanvasAndPost(MainThread.canvas);
				}
			}
		}
	}
}

Denk aan je AndroidManifest.XML. in onderstaande voorbeeld zit een intent-filter. Ik weet niet zeker of die hier op z’n plek is… Een intent-filter wordt gebruikt door het systeem om aan te geven op welke manier de applicatie om moet gaan met code die verzoekt ‘iets’ uit te voeren. (bijvoorbeeld een URL, of een share-actie). Omdat deze game-loop nog niets buiten de eigen code uitvoert, zou de intent-filter wegkunnen. Overigens : Als je advertenties gaat toevoegen in je game, moet je ook in je AndroidManifest aangeven dat je applicatie gebruik maakt van de permissies INTERNET en ACCESS_NETWORK_STATE… Daarover later vast wel meer.

AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="happyworx.nl.coppa"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".CoppaActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Als je deze code snippets op de juiste manier in je project hebt geplakt (en de background image hebt gemaakt!) dan kun je proefdraaien. Als het goed is zie je dan een scherm, gevuld met je background image. Door te spelen met de onDraw-routines kun je proberen andere objecten toe te voegen (maak eens een class die erg lijkt op de BackGndManager, maar gebruik voor de bitmap een kleiner plaatje, bijvoorbeeld).

..daarna ga je aan de slag met de OnTouchEvent routines. Elk object (als je mijn voorbeeld classes gebruikt) heeft een getX, setX, getY en setY. Met die stukjes code kun je de plaatsing van het object beĆÆnvloeden. Gebruik hiervoor de regel canvas.drawBitmap(bitmap, X – width/2, Y – height/2, null); in de draw routine van je object. De coƶrdinaten die je opgeeft in die regel staan voor de LINKER BOVENHOEK van de bitmap! Daarom trek ik er de breedte en hoogte gedeeld door 2 vanaf. Zo heb ik het object met het centrum op de aangegeven plek geplaatst.

In een volgende how-to hoop ik uit te leggen hoe je deze simpele gameloop kunt uitbreiden met bijvoorbeeld een appel. In die tutorial kijken we direct naar het herkennen van een botsing tussen twee objecten. Je hebt dan de basis voor aPpLeZĀ  šŸ˜€

aPpLeZ gepubliceerd in de Market

Link naar market

Het is zo ver.. weer een nieuwe game van mijn hand in de Market! De vakantie is nuttig geweest, vooral om even afstand te nemen en een Architectuurtje te maken. Dat bleek toch nodig. De code is nog steeds niet zo mooi als zou kunnen, maar het spelletje werkt en is volgens mij ook best leuk om te doen. Ik werk nog aan geluid (om het echt irritant te maken) en een deel-op-facebook knop voor je scores ;).

Andere verzoekjes? Roept u maar!

Dan even inzoomen op het verdienmodel (want uiteraard dient ook aPpLeZ bij te dragen aan het doel). Ik heb weer gekozen voor een in-App advertising model. Mijn vriendinnetje raadde me aan om full-screen ads te gebruiken tussen de levels in. Ik denk dat die inderdaad erg goed werken. Toch heb ik gekozen voor – voorlopig – bannerads. Vooral omdat de game nog niet voorziet in levels van verschillend moeilijkheidsniveau. Omdat er geen XML bestanden zijn die de Layouts vormen, was voor implementatie van de Advertisements nog best een truukendoos nodig.

In mijn Activity maak ik een RelativeLayout aan. Daar voeg ik zowel het GamePanel als de AdView aan toe ;

rl = new RelativeLayout(this);
rl.addView(new MainGamePanel(this));
rl.addView(adView); AdRequest adRequest = new AdRequest();
// Un-comment this for testing
// adRequest.addTestDevice(AdRequest.TEST_EMULATOR);
AppelzActivity.adView.loadAd(adRequest); setContentView(rl);

Vervolgens zet ik, vanuit een andere class, op het gewenste moment de visibility van de AdView
( AppelzActivity.adView.setVisibility(View.VISIBLE); )

Een bijzondere ‘bug’ (?) ; Ik laat de view later verdwijnen met een animatie. Als de adView helemaal weg is (uit het scherm) zet ik de Visibility op “GONE”. Toch blijft de view de clicks in die ruimte verwerken! In mijn emulator, als de advertentie allang verdwenen was, leidde een klik in dat gebied toch nog tot het openen van een browser en volgen van de advertentie-link. Natuurlijk niet de bedoeling. Na het verwijderen van de regel : animation.setFillAfter(true); . Was ook dit probleem opgelost.

Ik ben aan het overwegen om de volledige source van Applez op dit blog te zetten of via GitHUB beschikbaar te maken. Op die manier kun je zelf kijken wat erin zit om te her-gebruiken. Zou je daar iets mee kunnen? Laat dan even een reactie achter op dit bericht.

Virale marketing – ambitie, creativiteit, planning of toch Geluk?

Virale marketing is een marketingtechniek die probeert met behulp van bestaande sociale netwerken de bekendheid van een merk te vergroten (of positieve associaties te bewerkstelligen) op een manier die te vergelijken is met een virale epidemie. Het lijkt op mond-tot-mondreclame versterkt door het internet, waardoor snel en goedkoop een groot aantal mensen bereikt kan worden.

Als iedereen de reclame uiting naar minimaal Ć©Ć©n persoon doorstuurt, zal de campagne eeuwig door blijven gaan, of in ieder geval totdat alle ontvankelijke personen bereikt zijn. In de praktijk zal op een gegeven moment de voortplantingsquote kleiner dan 1 worden, waardoor de campagne uitsterft. Bij een voortplantingsquote van gemiddeld 0,7 zullen van elke 100 recent geĆÆnfecteerden er 70 de uiting doorsturen, die op hun beurt de uiting ook weer naar 49 personen doorsturen et cetera. Uiteindelijk zal een virale campagne met een voortplantingsquote van 0.7, die begon met 100 geĆÆnfecteerde personen, bij benadering 333 personen bereikt hebben. Je raadt hem al, goede virals hebben een voortplantingsquote van veel meer dan 1. En dan kan het hard gaan. Zie hier een prachtig voorbeeld.

Hieronder kandidaat-virals voor mijn Apps. Als je wilt, mag je deze zonder bronvermelding Twitteren, Facebooken, Hyven, MySpacen, Badooen, Cu2en, LinkedInnen, GooglePlussen, MSNnen, GetGlue-en, Netloggen, Diaspora-en, Flickren, Tumbleren, Xingen en alles wat ik nog vergeten ben. Je mag ze zelfs YouTube-en ;).

1 mei, de Kikker is weer vrij!

B2B Apps ; Something completely different

Ik ben architect. GĆ©Ć©n professionele App-Developer. Dat is slechts een hobby. Met mijn hobby richt ik me op de consumenten markt. Een overzichtelijke market. Het publicatie proces is kinderlijk eenvoudig, als je een beetje op het versiebeheer let. Het meeste werk zit in het ontwikkelen van de App.

Hoe anders is het met Business 2 Business applicaties! Als Business Process Architect, werk ik onder andere aan Smart Mobility proposities. Met deze diensten helpen we bedrijven en overheden de mogelijkheden van Apps en mobility te herkennen. In mijn rol als bedrijfsprocesarchitect kom ik spannende en leuke trajecten tegen. Op veel plekken zie ik ook wat er gebeurt als bedrijven onvoorbereid aan Mobile Solutions beginnen…

Veel bedrijven beginnen aan mobility oplossingen en laten dan onder andere een App bouwen. Net zoals in de vroege jaren ’90 websites werden gebouwd. Kleine bedrijfjes bouwen snel een App, maar geven de code niet prijs. Misschien zijn ze zelfs opgeheven als er iets gewijzigd moet worden. Ik wil niet alle app-bouwers over Ć©Ć©n kam scheren. Er zitten zeker goede bij. En… er zijn ook veel bedrijven die

Inmiddels weten we, in het geval van websites, dat we rekening moeten houden met een wijzigende wereld. We zien het belang van Content Management Systemen. We vinden het belangrijk dat websites op allerlei platforms werken. Die verworven kennis wordt vaak vergeten als er een App gebouwd wordt. Atos is zich bewust dat er een andere aanpak nodig is om een goede, toekomstvaste, oplossing te bieden.

Er zit een flinke wereld onder deze Apps voor ‘the workforce’. Er moet nagedacht worden over multi-platform (Android, iOS, Windows Phone, zelfs HTML5). Er kan behoefte zijn aan een omgeving waar de medewerkers op een beheerde wijze hun Apps kunnen vinden en installeren. Atos heeft daar een speciale oplossing voor. Die oplossing hebben we “MyMarket” genoemd. MyMarket is een company-branded App market. Medewerkers kunnen er, bijvoorbeeld gebaseerd op hun Active Directory groepslidmaatschappen, passende Apps vinden en downloaden.

Als er binnen het bedrijf een BYOD (Bring Your Own Device) beleid is, komt er nog een dimensie bij. Stel je voor dat een medewerker, die uit dienst gaat, jouw bedrijfsapp gewoon meeneemt op een mobiele telefoon! Met de Atos MyMarket kun je in dergelijke gevallen de App actief terugtrekken of onbruikbaar maken. Een aantal voordelen van de Atos MyMarket oplossing ;

  1. Het bedrijf heeft een algemeen overzicht van de zakelijke applicaties en gebruikers.
  2. Apps worden gecoƶrdineerd uitgeven en gedistribueerd.
  3. Gebruikers kunnen feedback vast leggen op een eenvoudige manier.
  4. Gebruikers krijgen een tool hun verplichte en aanbevolen apps te vinden en te installeren.
  5. Ze hebben toegang tot hun bedrijf apps, maar ook van derden. Zelfs als dat een licentievergoeding vereist.
  6. Gebruiker en werkgever zijn er zeker van dat de nieuwste versies geĆÆnstalleerd zijn.
  7. Applicaties worden gevalideerd op kwaliteit, het beleid of veiligheidsaspecten alvorens te worden gepubliceerd.
  8. De service is beschikbaar op de iOS-en Android-platforms, maar het kan ook draaien op de meeste andere smartphones en tablet-platformen.
  9. Het platform stelt de organisatie in staat processen efficiƫnter te ondersteunen met Mobility Solutions.
  10. Het bedrijf kan de mobiele oplossingen die haar medewerkers nodig heeft aanbieden in een veilige en vriendelijke omgeving.

De piramide geeft de situatie duidelijk weer. Atos ondersteunt bedrijven op alle niveaus van de piramide. Atos bouwt dus ook Apps! Onze aanpak is eenvoudig; we beginnen met het maken van een storyboard. Op die manier brengen we de end-user experience in beeld. Na het afstemmen van initiƫle functionele requirements wordt er iteratief ontworpen. Wil je meer weten over wat Atos voor jouw bedrijf kan doen? Neem dan eens contact met me op!

Atos is een internationale IT-dienstverlener met een jaaromzet van 8,7 miljard euro. Het bedrijf biedt werk aan 74.000 collegaā€™s in 42 landen. Wereldwijd levert Atos aan haar klanten hi-tech transactieservices, advies en technologie, systeemintegratie en managed services.

Atos focust op het aanbieden van zakelijke technologie, die klanten vooruit helpt en in staat stelt hun onderneming van de toekomst te creƫren. Atos is de wereldwijde IT-partner voor de Olympische Spelen en staat genoteerd aan de Paris Eurolist Market.

 

Architect-uur : hoofdzaak, noodzaak of ver-zaakt?

Op dit moment volg ik een opleiding tot Enterprise Architect. In de opleiding zitten mooie voorbeelden van Architecturen. Ook wordt aangegeven wat de waarde is en hoe het wel en niet moet. Natuurlijk zijn de sessies bij Atos interactief en vertellen deelnemers regelmatig over eigen ervaringen. In de App-Brouwerij die ik doe, maak ik eigenlijk nooit bewust een software architectuur. Dingetjes groeien langzaam – maar zeker – uit de klauwen ;). Uiteindelijk zit ik natuurlijk met de handen in het haar als ik een keer iets wil veranderen of weghalen. Waar zit dat-en-dat ook alweer aan vast? Voordat ik de tijd neem om alsnog (reversed engineering) een soort Software Architectuurtje te maken, ben ik alweer bezig met het volgende programmeer-projectje.

De afbeelding bovenaan deze post is de zogenaamde “Magic Roundabout” in Swindon. Hij is ontworpen door de Architect Frank Blackmore. Ik vind zelf de foto behoorlijk onoverzichtelijk. Wij hebben in Pijnacker een grote rotonde, die lijkt me beter ‘gearchitectuurd’ (http://g.co/maps/m8x7h). Als je kijkt naar de textuele omschrijving van de “Magic Roundabout”, valt het mee : “Vijf mini-rotondes, in een cirkel”. Een tekening ervan is weer een stuk gecompliceerder. Ik vraag me af of de asfalt-man en de stoomwals-man (of vrouw) aan Frank heeft gevraagd of hij wel helemaal goed bij zijn hoofd is… Punt blijft; als ik een dergelijk ontwerpje voor mezelf zou maken van elke applicatie die ik wil gaan maken, dan zou ik waarschijnlijk niet meer beginnen aan het programmeren. Dat lijkt dan veel te moeilijk. Uit zelfbescherming denk ik nu dus maar niet na over ontwerpen en architectuur… En begin ik gewoon met het kloppen van code.

Wat gebeurt er dan als je geen architectuur toepast? Tja, dat is te zien in mijn code. EĆ©n grote spaghetti-bende met booleans, loopjes en vooral ook logging. Op dit moment speel ik met de gedachte om tijdens het code-kloppen een side-note met ‘de-facto architectuur’ bij te houden. Zo zou ik in ieder geval van de belangrijkste entiteiten in mijn App bij kunnen houden wat ze doen, waar ze aan vast hangen etc. Aan de andere kant; ik heb het al druk genoeg met het leren van JAVA.. is het wel handig om in dit stadium al te leren hoe ik Software Architectuur moet beschrijven? Voorlopig maar even zo. Je weet nooit wat het uiteindelijk oplevert. Er is in de gebouwen-wereld een prachtig voorbeeld; Het Winchester House…

De man van mevrouw Winchester, William Wirt, was eigenaar van de bekende Amerikaanse wapenfabriek Winchester Repeating Arms Company. Hoewel dit wordt betwist, gaat het verhaal dat een paranormaal begaafd medium het volgende aan mevrouw Winchester verteld heeft : “Reis naar West en het bouw een huis voor jezelf en voor de geesten die zijn gevallen door de wapens van je man. Je moet nooit stoppen met de bouw van het huis. Als je doorgaat met het bouwen ervan, zul je voor altijd leven. Maar als je stopt, dan ga je dood. ” De weduwe stierf op September 5, 1922. Op dat moment is de bouw ook stilgelegd. Er is 38 jaar lang en voor 5,5 miljoen euro werk gedaan aan het huis (equivalent van ca. 71 miljoen in 2010!). 24 uur per dag, 7 dagen per week. Het huis heeft ongeveer 160 kamers, waaronder 40 slaapkamers, 2 zalen (afgerond een en een onvoltooide) en 47 open haarden, 10.000 ruiten en 17 schoorstenen. Omdat er geen tijd was voor een Architectuur, zijn er trappen die nergens uitkomen, ramen binnen in het huis en lichtkoepels in vloeren. Er zijn zelfs deuren die uitkomen op een blinde muur!

En? Is het huis waardeloos? Zeer zeker niet. Het trekt duizenden bezoekers per jaar en is een fantastisch wonder van vakmanschap! Ook al slaan sommige dingen als een tang op een slagroomtaart. Ik ben een blij man als het ook zo zal zijn met mijn Apps. Ik denk er maar niet teveel over na. Ik maak ze maar gewoon. Ze doen het šŸ™‚

PS. Over een Passief Inkomen gesproken; mevrouw Winchester ontving uit het eigendom van de Winchester Repeating Arms Company een inkomen van ongeveer $ 1.000 per dag (onbelast).

Promotie van FlashWords in FlitsWoorden

Terwijl ik werk aan een nieuw spelletje (Applez), merk ik dat FlitsWoorden toch op een paar punten nog verbeterd kan worden. De Engelse versie (FlashWords) loopt nog steeds niet naar verwachting. Mijn idee is nu, om FlitsWoorden aan te passen zodat het op een Tablet (10.1″) goed draait. Omdat ik toch dingen moet wijzigen, kan ik ook een nieuw scherm maken. Dit scherm moet eenmalig getoond worden als de App gestart wordt. In dat scherm (waarschijnlijk een dialog) zal ik de gebruiker wijzen op de mogelijkheid ook Engelse woordjes te oefenen.

Natuurlijk had ik de FlitsWoorden App tweetalig kunnen maken. Bijvoorbeeld met een extra kolom met woordjes in de andere taal. Een preference zou dan kunnen bepalen welke kolom wordt uitgelezen. Uiteindelijk lijkt dit me lastiger dan twee apps met elk hun eigen database. Bovendien werkt het aanbieden van twee losse apps qua marketing waarschijnlijk beter.

Ik ga je proberen te laten zien hoe ik de oplossing heb uitgewerkt (twee uurtjes, inclusief uitzoeken en vooral bugfixen op de Intent).

High level :

  1. Er moet een versienummer uitgelezen worden
  2. Als het versienummer anders is dan het laatst opgeslagen versienummer op de telefoon, moet een dialoog getoond worden
  3. De dialoog moet 3 opties hebben ; 1. Later (dialoog wordt volgende keer bij opstarten weer getoond); 2. Niet meer laten zien; 3. Naar de Market om de Engelse versie te downloaden

Ik begin met het maken van een class (Activity) waarin het dialoogje met de knoppen wordt gemaakt:

public class VersionChangeInfo extends Activity {

	private String VCI_PREFIX = "vci_";
	private Activity mActivity;

	public VersionChangeInfo(final Activity context) {
		mActivity = context;
	}

	private PackageInfo getPackageInfo() {
        PackageInfo pi = null;
        try {
             pi = mActivity.getPackageManager().getPackageInfo(mActivity.getPackageName(), PackageManager.GET_ACTIVITIES);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return pi;
    }

     public void show() {
    	// Versie uitlezen (getPackageInfo) en plaatsen in een variabele
        PackageInfo versionInfo = getPackageInfo();
        // Handige combinatie maken van de VCI_PREFIX en de Versie
		final String eulaKey = VCI_PREFIX + versionInfo.versionCode;
		// In de SharedPreferences (textbestand op device) houden we bij of het dialoog getoond moet worden
        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity);
        boolean hasBeenShown = prefs.getBoolean(eulaKey, false);
        if(hasBeenShown == false){
        	// Tonen van het dialoog
            String title = mActivity.getString(R.string.app_name) + " v" + versionInfo.versionName;
            // In de Strings.xml (values map) kun je de tekst opnemen die je in het dialoog wilt zetten
            String message = mActivity.getString(R.string.updates) + "\n\n" + mActivity.getString(R.string.eula);

            AlertDialog.Builder builder = new AlertDialog.Builder(mActivity)
                    .setTitle(title)
                    .setMessage(message)
                    .setPositiveButton("Ga naar Market", new Dialog.OnClickListener() {
                        public void onClick(DialogInterface dialogInterface, int i) {
                            // Dialoog in het vervolg niet meer tonen
                            SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(eulaKey, true);
                            editor.commit();
                            dialogInterface.dismiss();
                            // Naar de market gaan om FlashWords te installeren
                            // Hier kom ik verderop even op terug!
                            final Intent MyIntent = new Intent(Intent.ACTION_VIEW,
                      		Uri.parse("https://play.google.com/store/apps/details?id=happyworx.nl.Flashwords"));
                            startActivity(MyIntent);
                        }
                    })
                    .setNegativeButton("Later", new Dialog.OnClickListener() {
                    	// Voor een "Later" hoeven we helemaal niets te doen. Alleen het dialoog dichtgooien.
						public void onClick(DialogInterface dialogInterface, int i) {
                            dialogInterface.dismiss();
						}

                    })

                    .setNeutralButton("Niet meer tonen", new Dialog.OnClickListener(){
						public void onClick(DialogInterface dialogInterface, int i) {
                            // Zet in de preferences file de eulaKey boolean op True
							// Het dialoog wordt dan de volgende keer niet meer getoond
							SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(eulaKey, true);
                            editor.commit();
                            dialogInterface.dismiss();
						}
					})
                    ;
            builder.create().show();
        }
    }

}

Even terugkomend op;

final Intent MyIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=happyworx.nl.Flashwords"));
startActivity(MyIntent);

Dit heeft mij behoorlijk wat moeite gekost. Er is een aantal dingen waar je aan moet denken;
1. LET OP : Je emulator (Android AVD) heeft gĆ©Ć©n Market applicatie geĆÆnstalleerd. Als je dus een intent maakt voor een “market://…” URI, zul je altijd een foutmelding terugkrijgen (no activity found to handle Intent). Daarom is het handiger om een URL te gebruiken die begint met “http://…” of “https://…”. Dan kun je het gerust testen in je emulator.

2. De activity waar je het Intent inzet, moet in de AndroidManifest ook beschreven zijn met een <intent-filter>. Op die manier weet het systeem dat de activiteit intents moet kunnen afhandelen en op welke manier;

<activity
   android:name=".VersionChangeInfo"
   android:label="VersionChangeInfo"
   android:screenOrientation="landscape">
      <intent-filter >
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
</activity>

Daarna pas ik mijn hoofdactiviteit aan. Zo wordt na het laden van het scherm meteen de routine gestart die kijkt of de dialoog getoond moet worden :

		new VersionChangeInfo(this).show();

 

 

 

FlitsWoorden – Een onverwacht succes?

Niets zo leuk als voorlezen voor de kinderen. Op een zeker moment gaan de appeltjes van je oog ook zelf het lezen ontdekken. Maar voordat geen Donald Duck meer veilig is, moet eerst worden geoefend. Op school wordt gewerkt met ‘kernen’. Kleine woordjes, die worden aangeleerd en getest. De kernen in de App komen niet exact overeen met de school-kernen, maar ze zijn wel ongeveer van hetzelfde moeilijkheidsniveau.Als een klas het eind van een kern bereikt heeft, worden Ć©Ć©n-minuut leestesten afgenomen. Hoe meer woordjes het kind kan lezen in een minuut, hoe beter.

Rond dit idee zette ik FlitsWoorden in de markt. Ik had niet de verwachting dat het een groot succes zou gaan worden. Ik dacht dat ouders liever een boek zouden pakken om hun kinderen te helpen met lezen. Toch werd FlitsWoorden in 3 maanden tijd bijna 3.200 keer geĆÆnstalleerd! Het idee achter de app is vrij eenvoudig. Er wordt een woordje getoond. Als je tikt op het woordje, verschijnt het volgende woord. Eind maart 2012 maakte ik de extra test-functionaliteit; Een stopwatch die een minuut loopt en telt hoeveel woordjes er zijn gelezen.

Doordat de App op verschillende sites werd besproken en zelfs in nieuwsbrieven van basisscholen naar voren kwam, hoefde ik zelf qua marketing weinig te doen. Het af en toe sturen van een tweet naar een basisschool (of beter : de it-beheerder van die school) was voldoende.

TECHNIEK

FlitsWoorden bevat een interessante techniek voor het opslaan en ophalen van de woordjes. Een SQL Database wordt, samen met de applicatie, op de telefoon geĆÆnstalleerd. In die database staan de ca 3.500 woordjes. Het was een behoorlijke uitdaging om ervoor te zorgen dat de App ook te updaten was. Als een programma update plaatsvindt, hoeft de Database niet te worden vervangen. Als ik een nieuwe database op de telefoon wil installeren, dan zal ik de oude moeten verwijderen. Om dit te borgen, heb ik in de Database een versietabel opgenomen. In de App wordt de versie van de geĆÆnstalleerde database vergeleken met de versie van de database die in het pakket (.APK) zit. Als er een verschil is, wordt de database op de telefoon vervangen. In de code snippets laat ik zien hoe dat werkt.

In de eerste versie van FlitsWoorden, werd de Database gevuld op het moment dat de App voor het eerst werd opgestart. Dit duurde lang en was niet full-proof (als de telefoon uitgeschakeld werd, zou de database corrupt raken). Daarom heb ik besloten de database in te pakken bij de App (in de Assets-folder).

Qua lettertypen is FlitsWoorden ook een hele puzzel geweest. Ik wilde zo dicht mogelijk blijven bij het lettertype dat ook op school wordt aangeboden. Door een oerwoud van pedagogen, onderwijsdeskundigen, dyslexie-specialisten kwam ik uiteindelijk op 2 lettertypen. De App moest dus de keuze tussen deze 2 lettertypen mogelijk te maken. Ik kreeg van de deskundigen (die ik voor mijn eigen vermaak maar “Schriftgeleerden” noemde šŸ™‚ ) allerlei suggesties, die elkaar soms ook tegenspraken. Uiteindelijk moest ik denken aan mijn doel en besloot ik te stoppen met het onderzoeken van de onderwijskundige kant. De kindjes moesten zelf maar besluiten wat ze het liefst zouden lezen. šŸ˜€

VERDIENMODEL

FlitsWoorden maakt gebruik van in-app advertising. Onderaan het scherm worden advertenties getoond. Ik voelde me enigszins bezwaard. Was het wel ‘chique’ om geld te verdienen aan een App voor kinderen? Gelukkig merkte ik snel dat de advertenties die Google uitkoos om te laten zien, echt waarde toevoegden! Leuke vakanties, uitjes voor kinderen, remedial teaching. Echt bijzondere extraatjes in mijn App!

TIPS

  1. Laat je, zeker op belangrijke punten, adviseren door professionals. Door kennis te maken met deze mensen worden ook deuren geopend die anders misschien gesloten blijven.
  2. Kies met zorg de categorieƫn waarin je de App publiceert. Op basis van deze categorisering worden advertenties uitgekozen om te tonen. De juiste advertenties voegen waarde toe aan je App.
  3. De technische Architectuur van je App moet zoveel mogelijk fool-proof zijn. Als een eindgebruiker de App afbreekt, of onverwachte dingen doet, moet je App voldoende robuust zijn om daar op een correcte wijze op te reageren.

CODE SNIPPETS

Om een database-update makkelijk mogelijk te maken, moet worden gecontroleerd welke versie geinstalleerd is op de telefoon. Deze versie wordt vergeleken met de versie die in de .APK is opgenomen (PackedDBVersion). Als er verschillen zijn, wordt de database uit de APK naar de telefoon gekopieerd (overwrite).

public void CheckInstalledDBVersion() throws NullPointerException, IOException {
	try {	

		Cursor cursor = (Cursor) WoordData.fetchDBInfo();
		cursor.moveToFirst();
		InstalledDBversion = cursor.getString(0);
		cursor.close();
		WoordData.close();
		Log.d("Installed", "" + InstalledDBversion);
		Log.d("Packed", "" + PackedDBversion);

		} 

	catch (RuntimeException e) {
		InstalledDBversion = "00";
		Log.d("RTE", ".. but we've catched it!");
	} finally {
		if (InstalledDBversion.equals(PackedDBversion)) {
			Log.d("Check", "They are the same");
			initialiseDatabase = true;
			// Installed DBVersion == Packed DBVersion .. nothing happens
		} else {
			showDialog(DBCHECKFAILDIALOG);
			initialiseDatabase = false;
			copyDB();
		}
	}
}

Ook een leuk extra’tje ; De knop om de selectielijsten aan en uit te zetten verandert van functie (en dus ook het opschrift verandert). Als minder dan de helft van de kernen geselecteerd is, heeft de knop de functie “alles uitzetten”. Als meer dan de helft al ‘aan’ staat, verandert de functie van de knop in “alles aanzetten”. Zie hier de code;

private void ClearSelections() {
	Button btnClear = (Button) findViewById(R.id.btnClear);
	int count = this.listView.getAdapter().getCount();
	int countchecked = 0;
	for (int i = 0; i < al.size(); i++) {
		if (listView.getCheckedItemPositions().get(i))
		countchecked++;
	}

	if (countchecked > (count / 2)) {
	if (countchecked == count) {
		for (int i = 0; i < count; i++) {
			this.listView.setItemChecked(i, false);
		}

	} else {
		for (int i = 0; i < count; i++) {
			this.listView.setItemChecked(i, true);
			}
		}
	} else {
		if (countchecked == 0) {
			for (int i = 0; i < count; i++) {
				this.listView.setItemChecked(i, true);
			}
		} else {
			Log.d("", "minder dan de helft gecheckt");
			for (int i = 0; i < count; i++) {
			this.listView.setItemChecked(i, false);
			}
		}
	}
	// Save the new selections
	SavePreferences();
}

JollyJot XMas – Hoe een gratis versie meer oplevert.

Na het kleine succes van JollyJot, besloot ik een andere versie te maken die ik gratis zou aanbieden op de Android Market. Omdat ik een doel heb met mijn App-schrijverij, moet de app wel geld opleveren. Daarom besloot ik deze versie van JollyJot te voorzien van in-app advertising.

JollyJot XMas is een remake met een kerst-thema. De vraag die JollyJot XMas aan de gebruiker stelt is nietĀ  “Wat zou je doen met een miljoen?”, maar “Wat is jouw kerst-wens voor de wereld?” De werking van de app is exact identiek aan het origineel. Het invoegen van de advertenties was geen lastige opgave. Het Google platform AdMob is duidelijk gedocumenteerd en er zijn op Internet stap-voor-stap implementatiehandleidingen te vinden.

Het was interessant te onderzoeken of het advertentiemodel lucratiever is dan het betaalmodel. Na 8 dagen in de market was de gratis versie al net zo vaak geĆÆnstalleerd als de betaalde versie in 3 maanden! De advertenties leveren niet heel erg veel op. Je moet een flinke installed base hebben om een paar cent per dag te kunnen bijboeken. Het hoogtepunt van de advertentie inkomsten was rond de kerst (geen verrassing ;)). Toen op Ć©Ć©n dag de inkomsten boven $1 uitstegen, was voor mij de test geslaagd. Het advertentiemodel kĆ”n – mits de applicatie voldoende gebruikt wordt – veel meer opleveren dan een betaalde app.

TIPS

  1. Kies het goede advertentieplatform. Wil je dat je advertentieruimte altijd gevuld wordt? Vind je een hoge eCPM belangrijk?
  2. Plaats je advertentie op een handige locatie in je app. Als je bijvoorbeeld een spel maakt, misschien is de advertentie dan het best op z’n plek tussen twee game-levels in?
  3. Hoe gek het ook klinkt; een mis-click levert geld op. Toch : Plaats je advertentie niet zo dat een gebruiker erop moet klikken. Dat is in strijd met de Google voorwaarden en kan leiden tot verwijdering van je account!

Toen op Ć©Ć©n dag de inkomsten groter waren dan $1, was het voor mij al een succes!

CODE SNIPPETS

Het plaatsen van een advertentie in je App is niet moeilijk

    // Create the adView
    adView = new AdView(this, AdSize.BANNER, Constants.MY_AD_UNIT_ID);
    // Lookup your LinearLayout assuming itā€™s been given
    // the attribute android:id="@+id/mainLayout"
    RelativeLayout layout = (RelativeLayout)findViewById(R.id.RelativeLayout1);

    // Add the adView to it
    layout.addView(adView);
    // Initiate a generic request to load it with an ad
    adView.loadAd(new AdRequest());
    // Look up the AdView as a resource and load a request.
    AdView adView = (AdView)this.findViewById(R.id.adView);
    adView.loadAd(new AdRequest());

 

JollyJot, een Twitter Wrapper.. en.. To pay or not to pay!

Op 12 oktober 2011 publiceerde ik mijn 2e applicatie in de Android Market. Mijn vriendin is vaak bezig met onder andere Abraham Hicks. Ikzelf ben in 2007 NLP Practitioner geworden. Het idee iets ‘te bestellen’ in het Universum heeft me altijd erg aangesproken. Christenen noemen het bidden, anderen doen een wens bij een vallende ster. Abraham Hicks gebruikt de term “Rockets of Desire“. Het zette mij aan het denken; Wat als je de aandacht van heel veel Internet gebruikers zou kunnen combineren om jouw persoonlijke wens meer ‘gedachtenkracht’ te geven? Sommige filosofieĆ«n zeggen : “Wat je aandacht geeft, dat groeit“. Stel nu, dat je niet de enige bent die de aandacht geeft, maar 1.000 anderen ook. Of misschien wel 5.000?

Er is een snelle en simpele manier om je gedachten te delen met een grote groep mensen. Twitter. Het werd mijn doel een Twitter-achtige applicatie te schrijven, gebaseerd op het gedachtegoed van The Secret, Hicks, Anthony Robbins en vele anderen. Vrolijkheid speelt altijd een grote rol in mijn werk en mijn leven. De naam voor de App was dan ook snel gevonden; JollyJot. Ik heb besloten om de app iets meer toe te spitsen op een specifieke vraag. Wat zou jij doen met een miljoen? Toevallig maakte Talpa op dat moment ook een TV serie over dezelfde vraag. Misschien zou dit mensen zelfs naar de app toe bewegen?

Op hoofdlijnen werkt de app als volgt: De gebruiker voert een wens in. De app voegt een klein stukje aan die wens toe (een hashtag met een String). Het zo gemaakte regeltje wordt via de Twitter API onder het account van de eindgebruiker verstuurd. In de app zit ook een mogelijkheid om te lezen wat anderen hebben gewenst. De app toont simpelweg alle tweets die de gecreƫerde hashtag bevatten. Na uitgebreid testen, publiceerde ik de app in de market. Het was mijn vaste overtuiging dat echte Secret-lovers toch zeker wel 99 cent wilden neertellen voor deze prachtige app. Afgezien van verzadiging van de markt (de markt is groot!), stond niet veel een PI op basis van deze app in de weg. Niet veel bleek minder waar. Op dit moment (april 2012) hebben 10 mensen de app aangeschaft! Persoonlijk ken ik er 2 van de 10. De inkomsten zijn nog niet op peil, maar ik ben blij en ook best trots met het eerste tientje dat ik verdiend heb aan mijn Android App-schrijverij :).

Van JollyJot heb ik veel geleerd. De interactie met de gebruiker via het aanraakscherm, de manier waarop Android omgaat met variabelen en niet in de laatste plaats de kracht van de Twitter-API. Toch ook tegenvallers. De API blijkt niet altijd alle tweets te kunnen vinden (misschien een retentie-probleem). Het technisch ontwerp van de app bracht ook mogelijkheden tot misbruik met zich mee. Wie de ‘geheime’ hashtag kende, kon immers zonder de app te gebruiken toch berichten in de JollyJot-stream plaatsen. Het grote voordeel van JollyJot is geweest, dat de applicatie zich vrij makkelijk laat ombouwen tot een andere versie. Er zijn maar twee variabelen;

  • Het Artwork (de plaatjes en vormgeving)
  • De Twitter hashtag die wordt toegevoegd aan het bericht

Een mooie kans om een andere versie te maken, die ik gratis zou gaan aanbieden. Het zou mijn eerste kennismaking worden met het tweede grote verdienmodel van apps; in app-advertising!

TIPS

  1. Maak je app rond een idee of toepassing die je interesse heeft.
  2. Probeer een app als betaalde app in de market te zetten. Het geeft je vrij snel een indruk van de bereidwilligheid van anderen om voor het door jou gemaakte werk te betalen.
  3. Integreer Social Media in je App. Zorg dat de naam van je App in alle geplaatste berichten zichtbaar is. Hier is een how-to.
  4. Bedenk hoe je app makkelijk kan worden aangepast, zodat met weinig werk een heel nieuwe versie ontstaat.
  5. Maak in je app veel gebruik van de Log-functionaliteit (Log.d(“String”,”String”);). Het geeft je inzicht in wat je app doet.
  6. Schrijf commentaar in je code. Zo kun je later precies zien wat je bedoeling was met een stuk code.

CODE SNIPPETS

Het toevoegen van de ‘geheime’ hashtag aan het bericht van de eindgebruiker.

private String getTweetMsg() {
return ” would spend $1 million on ” + UserInput.getText().toString() + ” – #JJtx2 @JollyJot”;
}

Voorbeeld van een JSON query voor het ophalen van de tweets. hier ben ik lang mee bezig geweest. Ik heb ook gemerkt dat deze query niet erg betrouwbaar is. Ik heb tot op heden nog niet kunnen ontdekken waarom het soms wel, soms niet werkt. Later, in een ander project (TwitterFeed en Yahoo Piping), vond ik Topsy (http://otter.topsy.com) deze zoekmachine voor Twitter lijkt betere resultaten te geven. Ik zou de code moeten ombouwen om het te testen.. Maar ben te druk bezig met andere, nieuwe projecten. Waarover later meer šŸ˜‰

public ArrayList<Tweet> getTweets(String searchTerm, int page) {
String searchUrl =
“http://search.twitter.com/search.json?q=@”
+ searchTerm + “&rpp=100&page=” + page;

ArrayList<Tweet> tweets =
new ArrayList<Tweet>();

DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(searchUrl);

ResponseHandler<String> responseHandler =
new BasicResponseHandler();

String responseBody = null;
try {
responseBody = client.execute(get, responseHandler);
} catch(Exception ex) {
ex.printStackTrace();
}

JSONObject jsonObject = null;
JSONParser parser=new JSONParser();

try {
Object obj = parser.parse(responseBody);
jsonObject=(JSONObject)obj;
}catch(Exception ex){
Log.v(“TEST”,”Exception: ” + ex.getMessage());
}

JSONArray arr = null;

try {
Object j = jsonObject.get(“results”);
arr = (JSONArray)j;
} catch(Exception ex){
Log.v(“TEST”,”Exception: ” + ex.getMessage());
}

for(Object t : arr) {

String b = ((JSONObject)t).get(“text”).toString().substring(0, (((JSONObject)t).get(“text”).toString()).length()-19);

Tweet tweet = new Tweet(
((JSONObject)t).get(“from_user”).toString(),
b,
((JSONObject)t).get(“profile_image_url”).toString()
);
tweets.add(tweet);
}

return tweets;
}

 

Opzetten van een ontwikkelomgeving

“Waar moet ik beginnen als ik wil ontwikkelen voor Mobiele Telefoons?”, wordt mij vaak gevraagd. Na een grap over Apple en een dikke portemonnee verwijs ik dan snel naar dit blog šŸ™‚ . Dus. Hoe gaat dat nou?

Voordat je begint met de Android SDK (Software Development Kit), neem een ā€‹ā€‹moment om te bevestigen dat je computer voldoet aan de systeemvereisten. Misschien moet je de JDK installeren, als je die niet al hebt.

Ik beveel van harte aan te ontwikkelen in Eclipse IDE (Integrated Development Environment). Hier kun je Eclipse downloaden http://www.eclipse.org/downloads/ Je moet ook de Android Development Tools (ADT) Plugin installeren om voor Android te kunnen ontwikkelen. Daar kom ik straks op terug.

Het SDK (Software Development Kit) startpakket is niet een volledige ontwikkelomgeving. het omvat alleen de kern SDK’s. Daarmee kun je de rest van de SDK pakketten (zoals de nieuwste Android-platforms) downloaden.

Als je dat nog niet hebt gedaan, download dan de laatste versie van de SDK starter pakket van de SDK download pagina.

Als je een .Zip of. Tgz pakket (in plaats van de SDK installable .exe) hebt gedownload, pak deze uit naar een veilige locatie op je computer. Standaard worden de SDK-bestanden uitgepakt in een map met de naam android-sdk-machine-platform.

Voer nu de Windows Installer (.exe-bestand) uit. De installatie zal controleren of de juiste Java SE Development Kit (JDK) is geĆÆnstalleerd.

Noteer de naam en locatie van de SDK map op je systeem. Dit is dus de locatie waar de SDK geĆÆnstalleerd is. Je hebt die later nodig bij het opzetten van de ADTĀ  plugin en bij gebruik van de SDK gereedschap vanaf de command-prompt.

Android biedt een aangepaste plugin voor de Eclipse IDE, genaamd Android Development Tools (ADT), die is ontworpen om een krachtige, geĆÆntegreerde omgeving te bieden om Android applicaties te bouwen. Het breidt de capaciteiten van Eclipse uit. Zo kun je met Eclipse zelfs Android APK’s exporteren, al dan niet ondertekend voor publicatie in de Market.

Lees hier stap-voor-stap hoe je de ADT installeert.

De laatste stap in het opzetten van je SDK wordt met behulp van de Android SDK Manager (een tool opgenomen in het SDK starter pakket) uitgevoerd. Zo kun je essentiƫle SDK pakketten downloaden naar je ontwikkelomgeving.

De SDK maakt gebruik van een modulaire structuur dat de belangrijkste onderdelen van de SDKAndroid-platform versies, add-ons, gereedschap, voorbeelden en documentatie in een reeks los te installeren pakketten van elkaar scheidt. Het SDK starter pakket, dat je al hebt gedownload, bevat slechts een enkelvoudige verpakking: de nieuwste versie van de SDK Tools. Om een Android-applicatie te ontwikkelen, moet je ook minstens een Android-platform en de daarbij behorende platform tools downloaden. Dit wordt gedaan door de SDK-Manager.

Start de Android SDK Manager (
SDK Manager.exe bestand in de root van de Android installatie). Klik daarna op Installeren om de aanbevolen verzameling pakketten (en platforms) te accepteren en te installeren.

Gefeliciteerd! Je kunt nu gaan ontwikkelen. Hier is een online “Hello Android” tutorial, waar je direct mee kunt beginnen!

 

Android, iOS, Java, SDK, adWords, adMob, StackOverflow, NPE..

Eenmaal besloten dat ik mijn PI zou gaan verdienen met Apps, moest ik een paar keuzes maken. De verleiding is groot om te gaan zitten wachten op HET idee. De killer-app. De app die alle andere apps overbodig maakt. Uit ervaring weet ik inmiddels, dat er weinig gebeurt als je gaat wachten. Ondernemen is ook ‘gewoon beginnen’. En vallen. En weer opstaan. In de afgelopen 10 jaar is wel mijn houding en gedrag veranderd. Voldoende om niet in dezelfde valkuilen te stappen. Ik maak me geen zorgen. Er zijn vast genoeg nieuwe valkuilen te ontdekken. šŸ˜‰

Ik weet niets van JAVA. Ik weet niets van Apps maken. Ik weet niets van iOS. Ik weet niets van… Tja. Gewoon beginnen klinkt eenvoudig. En dat blijkt het ook te zijn! Google geeft je alle informatie die je nodig hebt. De keuze voor het platform was snel gemaakt. Als je voor Apple wilt ontwikkelen, moet je 99 dollar betalen.. per jaar! Als je bedenkt hoe je PI zich zal ontwikkelen, een te verwaarlozen bedrag. Bij Android (Google Play) kost een ontwikkel-account 25 dollar. Eenmalig. Een net iets meer te verwaarlozen bedrag. Apple modereert welke Apps gepubliceerd worden. Android (Google) niet. Dat betekent dat je, in het geval van Apple, moet voldoen aan allerlei richtlijnen. Bovendien duurt het publiceren van een App een paar dagen. Als je een Google App publiceert, kunnen je gebruikers binnen een paar uur de App al downloaden!

Zo’n developers account aanmaken is eigenlijk zo gebeurd. Het installeren van de ontwikkel-omgeving (Eclipse) valt ook wel mee. En dan begint het. Het programmeren van mijn eerste app was als een vakantie in China. Alle informatie om je heen is onbegrijpelijk. Je probeert structuren te ontdekken en vergelijkingen te maken. Per toeval vind je eenzelfde symbool op verschillende plaatsen. Je vangt gesprekken op in het openbaar vervoer. Ook daar leer je wat gebruikelijke omgangsvormen. Opeens merk je dat bepaalde dingen op z’n plek vallen. Je weet waar je de metro kunt vinden. Waar je eten kunt halen. Misschien kun je zelfs kleine zinnetjes maken.

Met de app ontwikkeling ging het net zo. public void start(){}; Ik had werkelijk geen idee wat daar stond. Om nog maar te zwijgen over @Override en private static boolean. Veel voorbeelden downloaden. Goed zoeken op forums als StackOverflow (let op de sociale conventies!). En gewoon maar Proberen (met de hoofdletter “P”). Nog steeds zijn er veel “JAVA-dingen”Ā  die ik niet begrijp. Als ik naar mijn eerste apps kijk, zie ik een dikke spaghetti-brij van code. Maar na verloop van tijd werd het schoner. Sneller. Duidelijker. Beheersbaar. Ik maak me op dit moment weinig zorgen om de code. Uiteindelijk zal een professionele ontwikkelaar een paar Kilobyte kunnen besparen ten opzichte van mijn broddelwerk. De eindgebruiker ziet het broddelwerk echter niet. Op dit niveau van App Ontwikkeling is er nauwelijks sprake van snelheidsverschillen tussen niet- en wel-geoptimaliseerde code. Dus; It’s the result that counts!

Op 5 oktober 2011 publiceerde ik “First Test Application KKoenen” onder de naam “HelloAndroid“. Ik ben ongeveer 5 uur bezig geweest met het ontwikkelen van deze App. Het was ook de eerste keer dat ik het Google-publicatieproces gebruikte. Tijdens het doorlopen van de publicatie, valt direct het hoge potentieel op. Publiceren naar China, Letland, Ivoorkust en ook IndonesiĆ« (JAVA šŸ˜‰ ). Je kunt geld vragen voor je App, je kunt hem ook gratis aanbieden. Daarover later meer.

Mijn “test-app” (die echt bijna niets biedt aan functionaliteit) is inmiddels (april 2012) meer dan 50 keer gedownload. In de omschrijving op de market vermeld ik duidelijk dat het een ‘stomme’ app is die niets doet. Toch vonden 53 mensen het de moeite waard om een moment te investeren in het bekijken van dit waarde’loze’ ding. Denk je eens in hoeveel mensen bereid zijn een (gratis?) download te doen als je ze echt iets kunt bieden!

TIPS
1. Door goed kennis te nemen van de ‘mores’ en hoe men met elkaar omgaat binnen een App Development community als StackOverflow, bouw je een fantastisch fundament voor het beantwoorden van al je vragen.

2. Ontwikkel voor Apple als je nu al een can’t-lose idee hebt (a-la WordFeud?), waar mensen voor willen betalen. Bedenk : het idee is niet de garantie voor succes. Er zijn veel WordFeud-achtigen die het niet gemaakt hebben. Je kunt ook gaan ontwikkelen voor Apple als je het niet erg vindt dat iemand anders beoordeelt of jouw App ‘de moeite waard’ is..

3. Zodra je iets tegenkomt wat je weet, deel je kennis dan. Door actief te delen en bij te dragen aan een community, wordt de kans dat je iets waardevols tegenkomt steeds groter.

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.JUST_TRY);
setContentView(new Panel(this));
}

 

De achtergrond, het doel en een warm welkom

Op 13-jarige leeftijd besefte ik, dat de sleutel tot zorgeloos leven onder andere ligt in het verwerven van een passief inkomen. Ik wist alleen nog niet dat het zo heette.

In 1992 was er nog geen groot, publiek ontsloten Internet. Er waren wel zg Bulletin Board Systemen (BBS). Op mijn 286 AT 6 Mhz kon ik met mijn 26 MB harde schijf met zo’n systeem opzetten. DataWave werd binnen 2 jaar een volwaardig BBS met 3 inbelpunten en een aansluiting op CachetNet en KroonNet (de e-mail van de vroege jaren ’90). Ik vond het geweldig mensen toegang te verschaffen tot “gratis” post, bestanden en nieuwtjes. Mijn eigen kosten liepen snel op: Een telefoonlijn (noodzakelijk om mijn ouders niet op de kast te jagen) en regelmatig nieuwe apparatuur om bij te blijven. De enige manier om de kosten te compenseren, was het verkopen van abonnementen. BBS gebruikers konden toegang krijgen tot afgeschermde functionaliteiten en gedeelten van het systeem door 20 gulden per jaar (met eventueel een staffelkorting) over te maken op mijn rekening.

Daar heb je het; een passief inkomen. Het systeem draaide, de electronische post werd midden in de nacht opgehaald en verspreid. De abonnees betaalden. Ik hoefde nauwelijks te werken om toch kostenvrij mijn BBS te opereren. Later kwamen Internet, email,

Honda SS 50 – Ook een prachtige hobby

vriendinnetjes, mijn tentamens, scoutingclubs, brommers en allerlei andere bezigheden…

Ik ben blijven ondernemen. Op mijn 22e had ik een fijn draaiende eenmanszaak. Op het hoogtepunt waren er 3 mensen aan het werk bij klanten. Ikzelf was ook volledig declarabel. 40 uur per week hard aan het werk om de veel te vroeg aangenomen back-office medewerker te kunnen betalen. Daarnaast de administratie, advertenties, werving en andere bedrijfsactiviteiten. Totdat de bubble barstte.

Nu, meer dan 10 jaar later besef ik me dat ik sindsdien nooit meer gewerkt heb aan het bewust creĆ«ren van zo’n passief inkomen. De kansen liggen nog steeds voor het oprapen. In oktober 2011 besloot ik dat het mogelijk moet zijn een significant inkomen te verwerven uit het ontwikkelen en exploiteren van Android Apps. Mijn doel : Android betaalt mijn hypotheek, mijn verzekering, belastingen en mijn energie. Kortom ; Al mijn woonlasten.

Welkom op dit blog. Ik zal proberen de (barre?) tocht naar een stabiel passief inkomen (PI) hier te documenteren. Het uiteindelijke doel ; Beantwoorden van de vragen :

1. Is het mogelijk om een stabiel PI te creƫren uit ontwikkeling en exploitatie van Android Apps?
2. Zelfs als je begint zonder kennis van programmeren?

.. Vanuit ƩƩn persoon, etc. etc. You get the general picture ;). Misschien zie je zelf ook wel een mogelijkheid om een PI te creƫren. Dat hoeft niet met een computer. Je kunt het ook doen door verhuur van panden of apparatuur. Misschien heb je een goed idee en kun je het patenteren. Misschien kun je de spijltjes van je balkon verhuren als advertentieruimte. Ook rente kun je beschouwen als een PI. Of, je koopt een oud zwembad, bouwt het om tot ballenbak, vraagt 6,50 entree en zet wat personeel neer om te verkopen en te managen..

Het is niet gezegd dat je niets meer hoeft te doen om je PI te behouden. Elk idee heeft onderhoud nodig. Ook mijn BBS moest ik een aantal keren per jaar goed onder handen nemen. De inspanning die een PI vraagt, is (per euro) als het goed is vele malen lager dan de inspanning die een baan in loondienst (per diezelfde euro) vraagt.

Als je hier meer over wilt leren, kan ik van harte het boek aanbevelen dat mijn vriendin ook aan mij gaf. Het heet “Rijke Pa, Arme Pa en geeft in 256 pagina’s weer hoe het zit met een Passief Inkomen. In een leuk geschreven, vlot te lezen boek ontkracht Robert Kiyosaki het fabeltje dat je een hoog inkomen moet hebben om rijk te worden. Daarnaast betwist hij de overtuiging dat je huis tot de activa behoort, laat hij ouders zien waarom ze niet op het schoolsysteem kunnen vertrouwen als het om onderricht over geld gaat. Bovendien leert hij je wat je jouw eigen kinderen over geld zou moeten leren… Als je ze een gezonde financiĆ«le toekomst wilt geven.

Klik hier om het boek te bekijken en eventueel te bestellen.
Leuk dat je meeleest en een hartelijke groet vanuit Kinderspeeltuin de Ballebak in Zoetermeer ;).

Passief Inkomen ; Voor je het weet maakt iemand reclame voor je Ballebak op z’n Blog!

 

If at first, the idea is not absurd, then there is no hope for itĀ  – Albert Einstein