Tutorials

Een Android app

In deze tutorial gaan we een native Android app maken. Dit zullen we doen met PHP voor het genereren van de data en met Java en XML voor het maken van de Android app. We zullen JSON als dataformaat gebruiken, dus lees eerst mijn JSON tutorial door. Er is geen kennis van Android/Java vereist, maar ik verwacht wel dat je wat van PHP afweet. Ik zal in dit simpele voorbeeld geen dynamische data (lees: database) gebruiken om te kunnen concentreren op de app. Als data zal ik een verzonnen nieuwsfeed gebruiken. Alle code is te vinden in de GitHub repo.

Pagina 1

Het serverside gedeelte

Om te beginnen gaan we het serverside gedeelte maken. Dit zullen een bootstrap- en een indexbestand worden. Ze zien er als volgt uit:
[code lang=php file=bootstrap.php]
<?php
header('Content-Type: application/json');
@ob_start();
set_exception_handler(function($exception) {
showError($exception->getMessage());
exit();
});

function showError($message) {
@ob_end_clean();
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
echo json_encode(array('error' => $message));
}

$dbh = new PDO('mysql:host=localhost;dbname=android_tut', 'android_tut', 'android_tut');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
?>
[/code]
[code lang=php file=index.php]
<?php
require_once 'bootstrap.php';

$query = $dbh->query('SELECT id,title,content,slug FROM articles ORDER BY id desc');

$data = array();
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$data[] = $row;
}

echo json_encode($data);
?>
[/code]

De SQL die hierbij hoort is:
[code lang=sql]
CREATE TABLE IF NOT EXISTS `articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8 NOT NULL,
`content` text CHARACTER SET utf8 NOT NULL,
`slug` varchar(20) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `articles` (`id`, `title`, `content`, `slug`) VALUES
(1, 'Lorem ipsum', 'Lorem ipsum dolor sir amet ', 'lorem-ipsum'),
(2, 'Welkom op mijn blog!', 'Beetje laat, eigenlijk was het vorige artikel te vroeg...', 'welkom');
[/code]
Pagina 2

Installatie Android SDK

Om Android apps te ontwikkelen, heb je als eerste de Android SDK nodig. Ga naar developer.android.com/sdk en download de ADT bundle. Deze bevat alles wat je nodig hebt om Android apps te maken waaronder Eclipse (een IDE), de SDK zelf en de tools. Pak de bundle uit op een plek waar je hem makkelijk terug kan vinden, het is geen installatie. Pak hem in Windows bijvoorbeeld uit in C:\adt-bundle-windows.

Om niet continu de volledige paden voor alle commando's in the hoeven typen, voegen we de SDK tools toe aan PATH. In Windows klik je met de rechtermuisknop op Deze Computer en kies je Eigenschappen. Klik daarna op Geavanceerd en daarna op Omgevingsvariabelen. Selecteer PATH in systeemvariabelen en voeg dit aan toe aan het einde:
;C:\adt-bundle-windows\sdk\platform-tools;C:\adt-bundle-windows\sdk\tools

Uiteraard moet je het goede pad erin zetten. Test het nu door een nieuw opdracht promptvenster te openen en 'adb devices' in te typen. Geeft het een de output ‘List of devices attached’, dan doet hij het. Geeft het een error, loop dan alle stappen nog eens na, of volg een van deze tutorials: Windows, Mac of Linux.

Typ nu in de opdrachtprompt ‘android’ in. Selecteer in dit venster Android 4.3 (API 18) -> SDK Platform. Klik dan op Install packages en accepteer de licenties.
Pagina 3

Een eerste start

Om te beginnen open je Eclipse. Deze staat in de adt-bundle-windows/eclipse map. Klik hier op eclipse.exe en als het goed is start Eclipse nu op. Om te beginnen klik je in het File-menu New -> Android Application Project. Als Application name voer je een naam in voor je app (zoals Android Tutorial) en bij package name voer je een uniek package name in. Dit is meestal iets in de vorm van com.koenv.phphulp of nl.phphulp.app. Laat alle andere dingen op de defaults staan en doe dat ook in alle andere schermen. Klik daarna op Finish.

Als het goed is zie je nu in de Project explorer links je project en in het midden zie je twee files genaamd MainActivity.java en activity_main.xml.

Om te beginnen moet je weten waarvoor alle bestanden/mappen dienen:
AndroidManifest.xml
In dit bestand staat alle informatie over de Android app beschreven waaronder machtigingen en activities (de schermen van je app).
src/
In deze map staat alle Java code, dus hierin staan je echte activities, in je manifest staat alleen een verwijzing ernaar.
res/
In deze map staan alle resources, zoals app-icoontjes, layouts en vertalingen.

Om te beginnen kan je proberen om je app te runnen.

Als je een Android-apparaat hebt, moet je deze aan je PC koppelen. Zet USB-Debugging aan in Opties voor Ontwikkelaars op je Android-apparaat en zorg dat de drivers geïnstalleerd zijn (http://developer.android.com/tools/extras/oem-usb.html). Voer nu in de opdrachtprompt ‘adb devices’ in en zorg dat er een apparaat staat. Ga nu naar Eclipse en klik op Run . Selecteer in dit venster ‘Android application’ en je app komt over een paar seconden tevoorschijn op je apparaat :).

Als je geen Android-apparaat hebt, open je de Android Virtual Device Manager via Help->Android Virtual Device Manager in Eclipse. Klik op New in dit venster en geef het een naam, een SD-kaart grootte en een platform. Klik op ‘Create AVD’ en klik op Start. Als je emulator is opgestart, ontgrendel je het scherm. Ga nu naar Eclipse en klik op Run . Selecteer in dit venster ‘Android application’ en je app komt over een paar seconden tevoorschijn op je apparaat :).

Gebeurt er niks als je op Run klikt, zorg er dan voor dat je in de tab van MainActivity.java staat.
Pagina 4

De layout

In Android bouw je layouts d.m.v. XML. Dit hoef je niet te gebruiken, en dat gaan we dan ook niet doen voor deze simpele tutorial. Open activity_main.xml en zorg dat de Graphical editor geselecteerd is. Verwijder de TextView waarop Hello World staat. Sleep nu vanaf Composite de ListView in het venster en zorg dat deze wordt toegevoegd in de bovenhoek. Dat is alles voor deze app! (activity_main.xml)

Als je nu de app runt, zie je niks. Dit gaan we veranderen. Voeg ten eerste een nieuwe class toe aan je package door rechts te klikken op je package en New -> Class te selecteren. Als name gebruiken we Article. Klik op Finish. Nu gaan we de fields toevoegen die we ook in de JSON hebben staan. Voeg dit dus toe in de class (ik neem aan dat de syntax niet geheel nieuwe voor je is, het lijkt erg op PHP):
[code lang=java file=Article.java]
private int id;
private String title;
private String content;
private String slug;
[/code]
Selecteer nu in het menu Source de optie Generate getters/setters. Selecteer hier alle velden en klik op OK. Selecteer nu ook in het menu Source de optie Generate constructor using fields. Vink ook hier alles aan. De volledige class is hier te vinden.
Pagina 5

Zorgen voor een lijstvuller

Om een lijst te vullen heb je in Android een adapter nodig. Een adapter zorgt ervoor dat je eigen objecten op een goede manier in een lijst weergegeven worden. In deze tutorial gaan we er zelf een bouwen. Maak een nieuwe class genaamd ArticleAdapter. Zorg er nu voor dat deze class BaseAdapter extend:
[code lang=java file=ArticleAdapter.java]
public class ArticleAdapter extends BaseAdapter {
[/code]
Nu komt er als het goed is een rood lijntje onder BaseAdapter. Dit komt omdat je hem nog niet hebt geïmport. Dit is vergelijkbaar met PHP's use statement voor namespaces. Ga met je muis over BaseAdapter en klik op Import 'BaseAdapter' (android.widget). Nu is het rode lijntje als het goed is weg, maar nu staat er weer een onder ArticleAdapter. Dit komt omdat BaseAdapter nog een paar abstract methods heeft die je moet overriden. Ga met je muis over ArticleAdapter en klik op Add unimplemented methods. Als het goed is komen er nu een paar methods bij. Als eerste gaan we zorgen voor een goede constructor en variables. Deze zien er als volgt uit:
[code lang=java file=ArticleAdapter.java]
private Context context;
private ArrayList<Article> items;

public ArticleAdapter(Context context, ArrayList<Article> items) {
super();
this.context = context;
this.items = items;
}
[/code]
De Context is de belangrijkste class in Android, met een Context kan je heel veel, en die hebben we in deze class dus ook nodig. Een ArrayList is een array, maar dan in objectvorm. De <Article> betekent dat deze ArrayList alleen Article objecten bevat. In de constructor callen we eerst de constructor van BaseAdapter en dan zetten we alles in deze class. Omdat er rode lijntjes onder de classnamen staan, druk je op de sneltoets Ctrl+Shift+O of ga naar Source -> Organize imports. Nu zijn de rode lijntjes weg, maar er staan nu gele lijntjes onder de variables. Dit komt omdat we ze nog niet gebruiken.

Nu gaan we de method getCount() implementen. Dat is eigenlijk heel simpel, je returnt de count van items, dus als volgt:
[code lang=java file=ArticleAdapter.java]
@Override
public int getCount() {
return items.size();
}
[/code]
Als het goed is nu ook meteen het gele lijntje onder items weg.

Nu gaan we getItem() implementen, hierbij hoef je alleen maar een object te returnen:
[code lang=java file=ArticleAdapter.java]
@Override
public Object getItem(int position) {
return items.get(position);
}
[/code]
Nu getItemId(). Bij ons zijn de IDs hetzelfde als de posities, dus dat is wel erg simpel:
[code lang=java file=ArticleAdapter.java]
@Override
public long getItemId(int position) {
return position;
}
[/code]

Nu het moeilijkste, de getView() methode:
[code lang=java file=ArticleAdapter.java]
/**
* Dit wordt gebruikt voor een hogere snelheid
*/
static class ViewHolder {
public TextView title;
public TextView text;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
// Zorg ervoor dat we een layout kunnen maken
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

// Zorg voor een standaard view met 2 regels
view = inflater.inflate(android.R.layout.simple_list_item_2,
parent, false);

// We gaan voor wat snelheid zorgen
ViewHolder viewHolder = new ViewHolder();
viewHolder.title = (TextView) view.findViewById(android.R.id.text1);
viewHolder.text = (TextView) view.findViewById(android.R.id.text2);
// En deze snelheid opslaan
view.setTag(viewHolder);
}

// Hier kunnen we de snelheid weer terugkrijgen
ViewHolder holder = (ViewHolder) view.getTag();

// Dit is ons artikel dat we moeten laten zien
final Article article = items.get(position);

// We gaan op de eerste regel een titel laten zien
holder.title.setText(article.getTitle());
// En op de tweede regel wat content
holder.text.setText(article.getContent());

// En nu gaan we zorgen dat er een 'Toast' verschijnt als je op het item
// klikt
view.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// Hier maken we een 'Toast'
Toast.makeText(
context,
"Je hebt op artikel " + article.getId()
+ " geklikt met slug " + article.getSlug(),
Toast.LENGTH_LONG).show();

}
});

return view;
}
[/code]
Druk weer eerst op Ctrl+Shift+O. Ik hoop dat je het begrijpt als je het commentaar leest. Zo niet, laat dan vooral een reactie achter.
Pagina 6

De lijst vullen

We hebben nu alle ingrediënten om de lijst te vullen, dus we zullen daar maar meteen mee beginnen. Open als eerste MainActivity.java.
Voeg als eerste een paar variables toe:
[code lang=java file=MainActivity.java]
// Onze list
private ListView listView;
// Onze artikelen
private ArrayList<Article> articles;
// Onze adapter
private ArticleAdapter adapter;
[/code]
Nu gaan we als eerste onCreate() aanpassen.
[code lang=java file=MainActivity.java]
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Zorg voor de goede layout
setContentView(R.layout.activity_main);

// Dit gedeelte is nieuw
// We willen een reference naar onze list vanuit onze layout
this.listView = (ListView) this.findViewById(R.id.listView1);

// We initialiseren eerst onze lijst van artikelen
this.articles = new ArrayList<Article>();
// Dan maken we daarmee onze adapter
this.adapter = new ArticleAdapter(this, articles);
// En dan zeggen we tegen de list dat onze adapter hem moet helpen :)
this.listView.setAdapter(this.adapter);
}
[/code]
Dit zorgt er dus voor dat we een reference naar onze list krijgen, dan een lijst van artikelen maken en deze via een adapter in de lijst laten zien.
Om te testen of dit werkt, kan je het volgende toevoegen aan het einde van de method:
[code lang=java file=MainActivity.java]
this.articles.add(new Article(2, "Mijn leven", "Lorem ipsum dolor sir amet", "mijn-leven"));
this.articles.add(new Article(1, "Welkom", "Dit is een artikel", "welkom"));
[/code]
Hiermee voegen we twee artikelen toe aan de lijst. Zorg ervoor dat je dit verwijdert als je het hebt getest. Crasht je app of werkt iets niet, vergelijk je code dan met die in de GitHub repo.
Zo zou het er ongeveer uit moeten zien:
[img=http://www.koenv.nl/phphulp/android/screenshots/1.png]

Nu gaan we zorgen dat onze lijst gereload wordt elke keer als het scherm zichtbaar wordt.
Voeg deze methods toe:
[code lang=java file=MainActivity.java]
@Override
protected void onResume() {
super.onResume();
// We reloaden de list telkens als het scherm zichtbaar wordt
this.reloadList();
}

/**
* Hier verversen we de lijst
*/
protected void reloadList() {

}
[/code]
Pagina 7

Verbinding met internet

Als eerste gaan we zorgen dat we überhaupt toegang tot het internet krijgen. Open AndroidManifest.xml en ga naar de tab Permissions. Klik op Add, selecteer Uses Permissions en klik op OK. Zoek in de lijst aan de rechterkant naar android.permission.INTERNET en sla het bestand op. Je hebt nu toegang tot het internet!

Nu gaan we zorgen dat je zelf niet al het moeilijke werk hoeft te doen om webpagina's op te halen. Ga naar http://loopj.com/android-async-http/ en klik op Download. Sla het bestand dat je download op in de libs map van je Android project. Ga nu weer naar Eclipse en rechtsklik op je libs-map en klik op Refresh.

Nu gaan we de method reloadList() implementeren. Als eerste maken we de HTTP Client aan en zorgen we voor een request (alles komt uit de library):
[code lang=java file=MainActivity.java]
protected void reloadList() {
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.koenv.nl/phphulp/android/index.php";,
new JsonHttpResponseHandler() {

});
}
[/code]
Je kan mijn server gebruiken of vervang http://www.koenv.nl/phphulp/android/index.php door je eigen URL. Hetgene wat deze method tot nu toe doet is een HTTP Client aanmaken, en dan een GET request sturen naar http://www.koenv.nl/phphulp/android/index.php. De response zal hier worden afgehandeld door de JsonHttpResponseHandler. De afhandeling gaan we nu maken. Als eerste gaan we zorgen dat de gebruiker een melding krijgt als er een fout is:
[code lang=java file=MainActivity.java]
protected void reloadList() {
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.koenv.nl/phphulp/android/index.php";,
new JsonHttpResponseHandler() {
@Override
public void onFailure(Throwable e, JSONObject response) {
try {
Toast.makeText(
MainActivity.this,
"Er is een fout opgetreden: "
+ response.getString("error"),
Toast.LENGTH_LONG).show();
} catch (JSONException e1) {
Toast.makeText(MainActivity.this,
"Er is een onbekende fout opgetreden",
Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Throwable e, String response) {
Toast.makeText(MainActivity.this,
"Er is een onbekende fout opgetreden",
Toast.LENGTH_LONG).show();
}
});
}
[/code]
Nu krijgt de gebruiker een 'Toast' met één van de messages die wij hebben geprogrammeerd. Er staan iets uitgebreidere methods in de GitHub repository zodat je beter kan debuggen als er iets fout gaat.

We gaan als laatste zorgen dat we een mooie lijst krijgen als het wel goed gaat :):
[code lang=java file=MainActivity.java]
protected void reloadList() {
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.koenv.nl/phphulp/android/index.php";,
new JsonHttpResponseHandler() {
@Override
public void onSuccess(JSONArray response) {
try {
// Leeg eerst alle articles
articles.clear();
for (int i = 0; i < response.length(); i++) {
// Nu willen we het JSON Object op de plaats i
JSONObject object = response.getJSONObject(i);
// Daarin zoeken we alle waarden op nodig voor
// ons Article object
int id = object.getInt("id");
String title = object.getString("title");
String content = object.getString("content");
String slug = object.getString("slug");
// Dan maken we ons Article object
Article article = new Article(id, title,
content, slug);
// En voegen we deze toe aan onze lijst
articles.add(article);
}
} catch (JSONException e) {
Toast.makeText(MainActivity.this,
"Er is een onbekende fout opgetreden",
Toast.LENGTH_LONG).show();
// Hiermee kan jij de errors zien in de view DDMS
// (rechtsboven klik je op DDMS in Eclipse)
Log.e("PHPHulp", response.toString(), e);
} finally {
// En hier zeggen we dat er iets is veranderd aan
// onze lijst en dat deze dus gerefresh moet worden
adapter.notifyDataSetChanged();
}
}

// hier de onFailure()
});

}
[/code]
Ik neem aan dat je ondertussen wel weet dat je altijd Ctrl+Shift+O moet proberen als er rode lijntjes ergens onder staan. Gaat het hiermee niet weg, ga dan over het rode lijntje en probeer of je de fout begrijpt. Zo niet, zoek het op op internet of vraag het in de reacties.
Pagina 8

Dat was het

Hiermee is onze app af, en kan jij hem gaan aanpassen aan je eigen wensen, zoals je eigen blog. Ik hoop dat het een beetje te volgen was, want voor de meesten is Java natuurlijk nieuw neem ik aan. Er zijn tutorials over Java te vinden bij Oracle.
Voor een ander tutorial over Android development, zie http://developer.android.com/training/basics/firstapp/index.html. Op deze officiële Android site voor ontwikkelaars staat ook heel veel informatie over Android development.
Heb je vragen, opmerkingen of ging er iets niet goed? Zet het in de reacties! Ik raad je nogmaals aan om ook in de GitHub repo te kijken.

Reacties

0
Nog geen reacties.