Categories
Dev

Android Tutorial7 min read

Kürzlich hatte ich das Vergnügen mich 1 Tag mit Google Android beschäftigen zu können. Dazu passend gibt es ein kleines Howto um auch anderen da draußen den Einstieg zu erleichtern. Voraussetzung für das Tutorial sind eine fertig installierte Eclipse IDE und Java Kenntnisse. Eine kleine Einführung was Android eigentlich kann und ist hab ich hier geschrieben.

Getting Started

Um starten zu können muss man sich erstmal das SKD Android von der Homepage laden. Dann wird das Eclipse Plugin hinzu gefügt. Das ist nicht unbedingt erforderlich, erleichter aber das arbeiten mit Android enorm. Plugins für andere IDEs gibt es leider derzeit noch nicht. Installiert wird das Android Plugin wie jedes andere Eclipse Plugin über die Update Funktionen:

  • Help > Software Updates > Find and Install….
  • Optioen “Search for new features to install” auswählen
  • Klick “New Remote Site
  • url eingeben: https://dl-ssl.google.com/android/eclipse/
  • Alle Packete auswählen, dann den Nutzngsbediengungen zustimmen und “Install All” klicken

Danach muss noch der Pfade zum Android SDK in den Preferences angegeben werden:

  • Window > Preferences..
  • In der Treeview links Android Suchen
  • dann unter SDK Location den Pfad wo es liegt angeben

Hello World Applikation



AndroidPIT

Neues Android Projekt anlegen

  • New Project → Android → Android Project
  • Name, Package etc. wie bei normalen Java Applikation

Es wird automatisch folgende Hello World App erstellt (Klasse ist wie gewohnt im src Ordner)

public class HelloAndroid extends Activity {
 
   @Override
   public void onCreate(Bundle icicle) {
      super.onCreate(icicle);
      setContentView(R.layout.main);
   }
}

Dieses einfache Beispiel besteht grob gesagt aus der HelloWorld Klasse und der R Klasse. Die R Klasse ist dabei die Repräsendation des XML Layouts, das in res/layouts/main.xml. Diese Klasse aktualisiert sich selbst sobald sich in den Layouts etwas ändert. Händisches editieren ist nicht empfohlen.

Ordnerstruktur

  • src (Source Klassen analog zu tradtionellen Java App)
  • assets
  • bin (kompiliertes Dalvik Executable (.dex) File
  • res
  • drawable (Grafiken, etc)
  • layout (xml Dateien mit View Informationen)
  • values (String Properties)
  • AndroidManifest.xml

Komponenten einer Applikation

  • Activities Repräsentieren Screen auf dem Handsets. Eine Activity kann auf User Inputs reagieren und besteht aus Views (UI). Eine abgeleitete Klasse extends Activity und man muss mit import android.app.Activity; importieren. Activities müssen im manifest definiert werden:
    <activity class=".MapSearch" android:label="@string/search"></activity>

    Soll eine Activity beim Starten des Programms ausgeführt werden kann man sie als Main mit einem Intent-Filter definieren:

    <activity class=".MapSearch" android:label="@string/search"></activity>
    <intent-filter></intent-filter>
    <action android:value="android.intent.action.MAIN"></action>
    <category android:value="android.intent.category.LAUNCHER"></category>
  • Intent definiert Ablauf einer Applikation. Stelle Action zur Verfügung/ URI. Beispiele: VIEW; EDIT. Request + Data Handling
  • Intent Filter Filtert die Weiterleitung eines Intent an eine spezielle Activity.
  • Intent Reciever Lauschen auf Ereignisse des Endgerätes. zb. Starten einer Applikation wenn Anruf eingeht. Ist unabhängig von der Applikation und wir im androidmanifest.xml definiert.
  • Service Stellt Funktionalität bereit die nicht umittelbar mit User-Interaktionen zu tun haben. zb. MP3 abspielen im Hintergrund. In diesem Fall ist die Activity das UI und das Service der MP3 Decoder und Player
  • Content Provider Interface für Standard Datenmanagements-Operationen

Tutorial

Auf der Android Homepage gibt es weiters ein schönes Tutorial, das die Basiskonzept von Android in einem netten kleinen Praxisbeispiel verpackt. Ich hab auch anfangs dieses Tut durchgearbeitet und kann es nur jedem empfehlen.

Google Maps Applikation

Für die Google Maps App ein neues Android Projekt anlegen:

Als ersten Schritt wollen wir uns nur mal eine Karte mit einem fix definierten Startpunkt ausgeben lassen. Für die Karten-Ausgabe gibt es in Android einen eigene MapView. Wir ändern die onCreate Methode der Hauptactivityklasse (bei mir mapapp.java) wie folgt:

private MapView map;
(...)
@Override
protected void onCreate(Bundle icicle) {
   super.onCreate(icicle);
   map = new MapView(this);
   // einen startpunkt der Karte als Point defnieren. Achtung: die Koordinatenpaare werden nicht  als double sondern als int gespeichert und müssen daher 10e6 multipliziert werden
   Point p = new Point((int) (48.416402 * 1000000), (int) (16.025078 * 1000000));
 
   // Der MapController Steuert die Aktionen mit der Karte
   MapController mc = map.getController();
 
   // zum defnierten Point p scrollen
   mc.animateTo(p);
 
   // Die Zoomstufe setzen
   mc.zoomTo(9);
 
   // Karte ausgeben
   setContentView(map);
 
}

Um eine Android Applikation zu starten müsst ihr beim ersten Mal eine Launch-Konfig erstellen. Dafür auf Run->Open Run Dialog.. klicken und die Einstellungen ähnlich meinen hier vornehmen
androidrun.jpg
Wenn ihr auf den Tab Emulator geht könnt ihr euch noch die visuelle Form des Android Emulators aussuchen. Abschließend auf Run klicken um den Build Prozess zu starten.

Nachdem der Android Emulator geladen ist, solltet ihr in etwa sowas sehen:
map.jpg

Als nächstes geben wir dem User einiges mehr an Kontrolle über die Karte. Wir implementieren Hotkeys für die wichtigsten Funktionen wie Zoomen und die Map-Modi wechseln:

public boolean onKeyDown(int keyCode, KeyEvent event) {
   if (keyCode == KeyEvent.KEYCODE_I) {
      int level = map.getZoomLevel();
      map.getController().zoomTo(level + 1);
      return true;
   } else if (keyCode == KeyEvent.KEYCODE_O) {
      int level = map.getZoomLevel();
      map.getController().zoomTo(level - 1);
      return true;
   } else if (keyCode == KeyEvent.KEYCODE_S) {
      map.toggleSatellite();
      return true;
   } else if (keyCode == KeyEvent.KEYCODE_T) {
      map.toggleTraffic();
      return true;
   }
   return false;
}

Als nächstes Feature wollen wir eine Suche in der Karte implementieren. Dazu machen wir im ersten Schritt ein Options-Menü, das uns zur Suchmaske leitet:

private static final int SEARCH_ID = Menu.FIRST;
private static final int ACTIVITY_SEARCH=0;
(...)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
   super.onCreateOptionsMenu(menu);
   menu.add(0, SEARCH_ID, R.string.map_search);
   return true;
}
 
@Override
public boolean onMenuItemSelected(int featureId, Item item) {
   super.onMenuItemSelected(featureId, item);
   switch(item.getId()) {
       case SEARCH_ID:
         Intent i = new Intent(this, MapSearch.class);
         startSubActivity(i, ACTIVITY_SEARCH);
         break;
   }
   return true;
}

in den strings.xml muss noch der String für den Wert “map_search” gesetzt werdeb:

<string name="map_search">Suche in der Karte</string>

Wie ihr sehen könnt starte ich nach dem Klick auf den SEARCH_ID Eintrag im Options-Menü eine Sub-Activity auf Basis der neuen MapSearch Klasse. Also mal eine neue Klasse anlegen mit New->Class. Die Klasse extended Activity und muss natürlich auch import android.app.Activity;. Ihr könnt jetzt händisch die onCreate() Methode schreiben oder im Optionen Menü mit Rechtsklick in den Editor-> Source -> Override/Implement Methods die gewünschten Methoden auswählen die überschrieben werden soll – in userem Fall nur die onCreate() Methode.

Für die Suche machen wir uns dann ein eigenes XML Layout:

 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="wrap_content">
	<LinearLayout android:orientation="horizontal"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content">
		<TextView android:layout_width="wrap_content"
			android:layout_height="wrap_content" 
			android:text="@string/search" />
		<EditText id="@+id/search" 
		  android:layout_width="wrap_content"
			android:layout_height="wrap_content" 
			android:layout_weight="1"/>
	</LinearLayout>
 
	<Button id="@+id/confirm" 
	  android:text="@string/confirm"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />
</LinearLayout>

Dazu dann noch die Klasse mapSearch ausimplementieren. Sie besteht aus einem einfachen Aufbauen des Layouts und Verarbeiten des OK Klicks, der die Suche abschließt:

private EditText search; 
private static final int ACTIVITY_DISPLAY=0;
public static final String KEY_ROW_ID = "search";
 
@Override
protected void onCreate(Bundle icicle) {
   super.onCreate(icicle);
   setContentView(R.layout.map_search);
   search = (EditText) findViewById(R.id.search);
   Button confirmButton = (Button) findViewById(R.id.confirm);
   confirmButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View arg0) {
         setResult(RESULT_OK, search.getText().toString());
         finish();
      }
   });
}

Für die Rückgabe der Such String zur Karten Activity benutzen wir die setResult Methode, die einen String an Daten zur Hauptactivity transportieren kann. Diesen String data werden wir dann in einem weiteren Schritt auslesen und die Suche auf der Karte visualisieren. Die strings.xml muss wieder um folgende Werte ergänzt werden:

<string name="confirm">OK</string><
string name="map_search">Suche in der Karte</string>
<string name="search">Suche</string><

auch im AndroidManifest muss die neue Activity definiert werden:

<activity class=".MapSearch" android:label="@string/search"></activity>

Als nächsten Schritt wechseln wir wieder zurück in die Hauptklasse des Projektes und fügen folgende Methode hinzu, welche die Such-Funktionalität zur Verfügung stellt:

private String search = "";
 (...)
private MapPoint search(String q) {
   MapPoint mapPoint = new MapPoint(map.getMapCenter().getLatitudeE6(),   map.getMapCenter().getLongitudeE6());
 
   Map myMap = new Map(getDispatcher(), null, 0, 0, 0, mapPoint,    Zoom.getZoom(map.getZoomLevel()), 0);
 
   Search search = new Search(q, myMap, 0);
   getDispatcher().addDataRequest(search);
   while (!search.isComplete()) {
 
   }
   MapPoint point = null;
   for (int i = 0; i &lt; search.numPlacemarks(); i++) {
      Placemark placemark = search.getPlacemark(i);
      point = placemark.getLocation();
   }
   return point;
}

Die Methode nutze für die Suche das Search Objekt. Beim Instanzieren wird der Suchbegriff und ein MapView Objekt übergeben. Dieses kann aus ??? Gründen nicht die gerade aktive Karte sein, sondern muss ein extra dafür instanziertes Objekt sein. Darum der etwas seltsame Code. Wie schon vorher angesprochen muss jetzt nur noch der Such String aus der Such Activity übernommen werden. Das passiert in der Methode onActitivityResult welche den data String aus der Such Activity empfängt und die Suche ausführt:

@Override 
protected void onActivityResult(int requestCode, int resultCode, String data, Bundle extras) {
   super.onActivityResult(requestCode, resultCode, data, extras);
   search = (String) data.toString();
   if (search != null) {
      MapPoint point = this.search(search);
      if (point != null) {
         MapController mc = map.getController();
         Point point1 = new Point(point.getLatitude(), point.getLongitude());
         mc.animateTo(point1);
         mc.zoomTo(12);
      }
   }
}

Damit wäre einmal das Map Beispiel soweit fertig. Was noch im Code fehlt ist eine Fehlerbehandlung der Suche oder das Handling bei mehreren Suchergebnissen.

Das fertige Projekt könnt ihr auch noch downloaden: mapapp.rar

Ressourcen

Offizielle Homepage
Blog
Download Seite
API Dokumentation
Tutorial
User Gruppe

13 replies on “Android Tutorial7 min read

Super! Weiter so! Neulinge wie ich sind um jedes derartige Tutorial froh 🙂

Hallo,

ich Entwickle unter sdk_m5-rc15_windows und bei mir treten 3 Probleme auf:

1) Das Manifest-File ist nicht mehr aktuell. Hierzu muss man einfach die class=”” in android:name=”” ändern.

2) Das zweite Problem ist die Methode search: der Datentyp search und Datentyp Placemark nicht funktioniere. Dies habe ich erstmal gefixt durch einen statischen MapPoint der zurückgegeben wird. Ist zwar nicht der Sinn aber sollte gehen.

3) Das dritte Problem konnte ich bisscher nicht lösen: Und zwar erhalte ich zur laufzeit beim starten der sub activity folgende exception:

Application Error
at.erichholzbauer.android

An error has occured in at.erichholzbauer.android.
Unable to start activity
ComponentInfo{at.erichholzbauer.android/at.erichholzbauer.android.MapSearch):
java.lang.NullPointerException.

bissher habe ich den fehler darin nicht gefunden… Eine kurze antwort würde mir sehr helfen.

MfG

Pascal

Ich würde mich echt freuen, wenn der code überall kommentiert wäre und nicht nur am Anfang wo die map angelegt wurde. Wäre das möglich?

Halo ! echt schönen Blog besitzt du . Ich selber habe vor kurzem eine HTML-Seite programmiert, eine Suchmaschine. Gerade noch aufrufbar durch beta.jerome.de. Fände ich nett von dir wenn du mir sagst was du von ihr hälst bzw. was noch verbesserbar darauf ist. Ein Design kommt erst im Laufe der Woche hinzu. Danke – 345zhf4

Der Tutorial Link für ein weiteres Tutorial ist tot 🙁
Bin noch gerade dein Tutorial am durchgehen, bis jetzt ist alles gut verständlich, danke.

Leave a Reply

Your email address will not be published. Required fields are marked *