Einführung in Android März 2015 | Anke Visser 1 Android Eigenschaften Android ist ein auf Linux basierendes Betriebssystem für Smartphones und Tablets Android ist freie Software Android bietet eine Java Programmierschnittstelle Mit dem AndroidSDK wird eine Entwicklungsumgebung für Unix oder Windows bereitgestellt (Compiler, Debugger, Emulator) 2 Dokumentation http://developer.android.com API, Tutorials, Styleguides und vieles mehr http://developer.android.com/reference http://developer.android.com/resources http://www.androidbuch.de/ Deutsches Buch, eine alte Version ist als pdf kostenlos erhältlich – – HINWEIS: Die bisher in Java genutzte API steht in Android nur teilweise zur Verfügung. Es gibt z.B. das Paket java.util, aber es enthält nicht alle Klassen der Java Standardbibliothek. 3 Arbeitsumgebung: Eclipse mit ADT Android SDK (http://developer.android.com/sdk) Eclipse Plugin: Android Development Tools (ADT) Generiert automatisch alle benötigten Dateien Konfiguriert und startet Emulator Erzeugt apk Datei (Android Package) Installation (im Ausbildungsraum bereits installiert) Vorhandes Eclipse: – Download and install SDK – Menü Help->Install New Software – Work with: https://dl-ssl.google.com/android/eclipse/ – Window->Preferences->Android : SDK Location Window->Android SDK Manager Auswahl der gewünschten Android-Version (abwärtskompatibel? Vorschlag: 4er Version) 4 Erstellen eines Emulators in Eclipse/Android Studio Eclipse: Window->Android Virtual Device Manager Button „New“ wählen, Fenster „Create new Android Virtual Device“ wird aufgerufen Target: Android-Version – ggf. Auflösung des eigenen Gerätes eintragen – ggf. weitere Emulatoren mit anderen Android-Versionen und Auflösungen zum Testen Der Emulator kann mit „Start“ aufgerufen werden. – Android Studio: Tools->Android->AVD Manager Hinweis: Das Anlegen eines Emulator dauert auf den Maschinen im Ausbildungsraum ggf. etwas länger 5 Das erste Projekt (Eclipse) Application name: LaengenRechner, package name: matse.projekt Eclipse: Erstellen Sie einen eigenen Workspace für Ihre Android-Projekte File->New->Other... Select a wizard: Android ->Android Application Project New Android Application Project Testen auf dem Emulator: Starten des Emulators Run as Android Application, oder falls nicht vorhanden: – Run Configurations → Android Application erstellen AndroidStudio: File->New Project Auwahl: "Phone and Tablet" + API version Auswahl: "Blank aktivity" 6 Projektstruktur eines Android-Projektes Die Projektstruktur wird von Eclipse/Android Studio erzeugt: src: Quelldateien ( unter Android Studio: java ) res: Resourcen drawable: Bilder in verschiedenen Auflösungen – layout: Oberflächenelemente – values: In der App benutzte Texte (=>Internationalisierung) AndroidManifest.xml Startpunkt und alle Eigenschaften und Rechte sind hier beschrieben – Beim Build-Prozess erzeugte Ordner und Dateien gen: automatisch generierte Quelldateien, z.B. R.java bin: LaengenRechner.apk (Installationsdatei, nur Eclipse) 7 Projektstruktur Beispiel 1. Projekt: LaengenRechner Activity (.../src/matse/projekt/LaengenRechnerActivity.java) Subklasse von Activity Komponente, die Benutzerinteraktion realisiert Main-Activity wird beim Anlegen eines Android Projektes automatisch erzeugt und in das Manifest eingetragen onCreate() ist der Startpunkt der Activity View (LaengenRechner/res/layout/main.xml) XML-Datei oder Java-Datei XML-Datei legt die Komponenten der Oberfläche und ihr Layout fest Activity greift auf diese Komponenten zu 8 LaengenRechnerActivity.java Die erste Activity wird von Eclipse automatisch erzeugt: package matse.projekt; import android.app.Activity; import android.os.Bundle; public class LaengenRechnerActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } R.layout.main ist eine Referenz auf res/layout/main.xml und wird von Eclipse erzeugt und in Klasse R automatisch verlinkt. 9 R.java In der Klasse R werden alle Resourcen des aktuellen Paketes verwaltet und mit einer eindeutigen ID versehen. R.java wird automatisch erzeugt enthält Verweise auf alle Resourcen aus dem Ordner res, z.B. – – – – Views, die in der inneren Klasse R.layout verwaltet werden, z.B. die Hauptansicht R.layout.main IDs innerhalb der xml-Dateien @id/name → R.id.name Bilder, die mit R.drawable.bildname angesprochen werden Strings die in der inneren Klasse R.string aufgelistet werden 10 Aufgabe: LaengenRechner Erstellen der GUI res/layout/main.xml auswählen Tab wählen: Graphical Layout/Design[ [Form] Widget: 2 Radiobuttons: cm->inch inch->cm erstellen Text Fields: 2 Textfelder double-Eingabe cm und inch [Form] Widget: 1 Button mit Text ok Alle Eingabefelder müssen mit sinnvollen Namen versehen werden, um sie in der Activity ansprechen zu können 11 main.xml <?xml version="1.0" encoding="utf­8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Längenmaßumrechner" android:textSize="24sp" /> <RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content" > <RadioButton android:id="@+id/meter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Zentimeter ­> Inch" /> 12 LaengenRechner Erweitern der Activity public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // layout aus main.xml setzen // Gui­Elemente aus res/layouts/main.xml suchen RadioButton meter = (RadioButton) findViewById(R.id.meter); RadioButton inch = (RadioButton) findViewById(R.id.inch); EditText bmeter = (EditText) findViewById(R.id.bmeter); EditText binch = (EditText) findViewById(R.id.binch); Button ok = (Button) findViewById(R.id.ok); // ok­Button soll auf Klick reagieren ok.setOnClickListener(new OkClick()); } 13 Listener Zur Reaktion auf Benutzereingaben werden Listener benötigt. Die Klasse Button stellt die folgende Methode bereit: void setOnClickListener(View.OnClickListener l); Beim Klicken auf den Button wird von der Klasse Button die Methode onClick aufgerufen. public interface OnClickListener { public void onClick(View v); } Der Listener kann z.B. als innere Klasse implementiert werden: public class OkClick implements OnClickListener { public void onClick(View v) { System.out.println(“Button wurde geklickt“); } } 14 Aufgabe Erstellen Sie für die Arbeit mit Android einen separaten Workspace in Eclipse. Implementieren sie den Längenrechner. Der Benutzer wählt zuerst ob Inch oder cm angegeben werden Danach wird in das entsprechende Eingabefeld der umzurechnende Wert eingegeben Nach Drücken des „Ok“-Buttons wird der entsprechende Wert in Inch oder cm berechnet und in das passende Textfeld eingetragen 15 Komponenten / Activities Bisher bestand das Programm nur aus einer Komponente. Android-Programme bestehen aus einer oder mehreren Komponenten (z.B. Activities) Diese Komponenten können von anderen Komponenten des Programms aktiviert werden können auch von fremden Programmen aktiviert werden können Informationen vom Aufrufer erhalten und Informationen an den Aufrufer zurückgeben müssen im Manifest des Programms deklariert werden 16 Weitere Activities und Views erzeugen Eine neue Activity mit zugehöriger View kann mit File->New ->Other...->Android Activity erzeugt werden. Sie ist Subklasse von android.app.Activity. Die neue Activity muss in AndroidManifest.xml eingetragen werden, was bei Eclipse automatisch erfolgt. <activity android:name=".MeineActivity" > </activity> Zum Erzeugen einer weiteren View wird eine xml-Datei benötigt File->New- > Other...-> android XML file 17 Kommunikation mit Intents Starten einer Activity Eine neue Activity mit dem Klassennamen NextActivity soll aufgerufen werden. Dazu wird ein Intent-Objekt benötigt. public Intent(Context packageContext, Class<?> cls) 1. Parameter: Objekt der aufrufenden Activity denn jede Activity ist Subklasse von Context 2. Parameter: die aufzurufende Klasse Intent intent = new Intent(this,NextActivity.class); startActivity(intent); 18 Kommunikation mit Intents Starten einer Activity, Übergabe von Werten Einem Intent können Werte hinzugefügt werden: Intent intent = new Intent(this, NextActivity.class); intent.putExtra("text", "Ein Text"); intent.putExtra("zahl", 7); startActivity(intent); 19 Intents Lesen der übergebenen Werte Das mitgegebene Intent-Objekt kann in der neu aufgerufenen Activity ausgelesen werden: public class NextActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); String text = intent.getStringExtra("text"); int zahl = intent.getIntExtra("zahl", 0); System.out.println("Werte bekommen: "+text+","+zahl); } ... 20 Kommunikation mit Intents Rückgabewert einer Activity Beim Aufruf einer Activity kann ein Ergebnis erwartet werden. In diesem Fall wird die Methode startActivityForResult aufgerufen und als 2. Parameter eine eindeutige ID übergeben. private static final int MYID = 1; ... Intent intent = new Intent(this,NextActivity.class); startActivityForResult(intent, MYID); 21 Intents Rückgabe eines Ergebnisses Beim Beenden einer Activity kann ein Rückgabewert über ein Intent gesetzt werden. Zusätzlich wird ein Resultcode mit den Werten RESULT_CANCELED oder RESULT_OK gesetzt. public class NextActivity extends Activity { ... private void ende(int zahl) { Intent returnIntent = new Intent(); returnIntent.putExtra("value", zahl); setResult(RESULT_OK, returnIntent); finish(); } } 22 Intents Ergebnis bearbeiten Aufruf der Activity mit startActivityForResult(intent, MYID); Nach Beenden einer Activity mit Ergebnis wird die Methode onActivityResult des Aufrufers aufgerufen. [1] public void onActivityResult(int requestCode, int resultCode, Intent data) { [2] switch (requestCode) { [3] case MYID: [4] switch (resultCode) { [5] case Activity.RESULT_OK: [6] double wert = data.getIntExra("value", 0); [7] System.out.println("ok: "+wert); [8] break; [9] case Activity.RESULT_CANCELED: [10] System.out.println("cancel"); break; [11] } [12] break; [13] } 23 [14] } Zeichnen Die Methode onDraw der Klasse View wird überschrieben: [1] public class Drawing extends View { [2] ... [3] public void onDraw(Canvas canvas) [4] { [5] Resources res = this.getContext().getResources(); [6] Drawable image = res.getDrawable(R.drawable.cardback); [7] int x = 50, y= 50; [8] image.setBounds(x, y, image.getIntrinsicWidth()+x, [9] image.getIntrinsicHeight()+y); [10] image.draw(canvas); [11] } Das gezeichnete Bild ist eine png-Datei, die in den ResourcenOrdner res/drawable kopiert wurde. Die dort stehenden Dateien (Kleinbuchstaben!) können unter R.drawable angesprochen werden. Die Dateiendung muss weggelassen werden. 24 Reaktion auf Tasten/Touch/Klick Weitere Listener müssen registiert werden: [1] public class Drawing extends View implements OnTouchListener, [2] OnKeyListener { [3] public Drawing(Context context) { [4] super(context); [5] setFocusable(true); [6] setFocusableInTouchMode(true); [7] this.setOnTouchListener(this); [8] this.setOnKeyListener(this); [9] } [10] public boolean onKey(View v, int keyCode, KeyEvent event) { [11] System.out.println("key event: "+event); [12] return false; // nicht bearbeitet => weiterleiten [13] } [14] // handles movement, for klick use onClickListener [15] public boolean onTouch(View view, MotionEvent event) { [16] System.out.println("pos: "+event.getX() + "," [17] +event.getY()); [18] return true; [19] } 25 Activity Lifecycle Eine Activity kann sich in verschiedenen Zuständen befinden. Die wesentlichen Zustände sind resumed Die Activity läuft im Vordergrund paused Eine andere Activity bekommt den Fokus, die Activity bleibt aber sichtbar. Exklusive Resourcen (z.B. Kamera) sollten freigegeben werden, rechenintensive Threads beendet werden. stopped Die Activity ist nicht mehr für den Benutzer sichbar. destroyed Die Activity wurde endgültig beendet. Im Notfall (zu wenig Speicher vorhanden) kann das System die Activity in den letzten drei Zuständen sofort beenden, so dass kein Code dieser Activity mehr ausgeführt wird. 26 Activity Lifecycle 27 Datenhaltung Applikationen nutzen oft eine zentrale Klasse zur Verwaltung der Daten, z. B. Model-View-Controller In Android ist jede Activity ein eigenständiges Element, die Datenübergabe in Form von Referenzen ist nicht möglich. Möglichkeiten der Datenkommunikation zwischen Activities Intents (s. Kommunikation mit Intents) Speichern der Daten an einem zentralen Ort 28 Daten sichern Möglichkeiten Daten persistent zu speichern Shared Preferences (Schlüssel-Werte-Paare) Vorteil: einfach, für einfache Daten ausreichend Interner Speicher (nur für die eigene App lesbar) Externer Speicher (z.B. SD-Card, USB-Stick) Datenbank (SQLite) Temporäre Datenhaltung Erstellen einer Singelton-Klasse (Klasse mit nur einer Instanz), die von allen Activities genutzt wird. Dies bietet die Möglichkeit komplexe Datenstrukturen zur Verfügung zur stellen. 29 IO mit SharedPreferences Beispiel: Spielstand sichern [1] import android.content.SharedPreferences; [2] import android.app.Activity; [3] [4] public class MainActivity extends Activity [5] { [6] private SharedPreferences prefs; [7] static final String PREF_NAME="MyPrefs"; [8] [9] protected void onCreate(Bundle savedInstanceState) { [10] super.onCreate(savedInstanceState); [11] [12] prefs = getSharedPreferences(PREF_NAME, 0); [13] int intValue = prefs.getInt("nummer", ­1); [14] System.out.println("read value from preferences: "+intValue); [15] [16] SharedPreferences.Editor editor = prefs.edit(); [17] editor.putInt("nummer", intValue+1); [18] boolean ok = editor.commit(); [19] System.out.println("Success writing to preferences: "+ok); [20] } [21] } 30 SharedPreferences Die mit getSharedPreferences(“prefs“, 0) angesprochene Datei /data/data/PaketeName/shared_prefs/prefs.xml kann im Emulator angesehen und editiert werden: Das folgende Kommando öffnet eine Shell für den Emulator: adb shell Alternative Ansicht in der DDMS perspective in Eclipse (File Explorer) 31 I/O Die Methode openFileInput() von android.content.Context kann direkt aus einer Activity aufgerufen werden. Die Datei liegt unter /data/data/package/files/dateiname. [1] try { // Lesen [2] FileInputStream fin = openFileInput(dateiName1, MODE_PRIVATE); [3] Scanner in = new Scanner(fin); [4] while (in.hasNextLine()) { [5] idx = in.nextInt(); [6] } [7] // Schreiben [8] FileOutputStream out = openFileOutput(dateiName2, MODE_PRIVATE); [9] String inhalt = ... [10] out.write(inhalt.getBytes()); [11] out.close(); [12] } catch (IOException e) { [13] e.printStackTrace(); [14] } 32 Fehler und mögliche Ursachen R.java wird nicht erzeugt/aktualisiert import android.R; Dieser Import darf nicht im Source stehen, wird aber unter bestimmten Unständen von Eclipse vorgeschlagen. 33 Prioritäten beim Projekt Funktionalität vor Design Listen, Buttons... sehen im Default-Theme nicht sehr dekorativ aus, können aber im Nachhinein durch zentrale Themes angepasst werden. Lauffähigkeit und Fehlerfreiheit vor Features Weitere Features können beim Entwurf eingeplant werden. Vor deren Implementierung muß die Implementation der Hauptfunktionalität aber abgeschlossen sein. 34 Aufgabe: Activities Der Prototyp eines Lernprogramms soll erstellt werden Erstellen Sie dazu eine View und eine zugehörige Activity. Die View soll zwei Buttons mit den Label „Addition üben“ und „Subtraktion üben“ enthalten. Zusätzlich enthält sie ein Ausgabeelement mit der Anzahl der korrekt bearbeiteten Aufgaben. Nach Auswahl eines Buttons soll eine neue Activity gestartet werden, in der eine zufällige Aufgabe gestellt wird. Die Activity bekommt die Information übergeben, ob eine Addition oder Subtraktion geübt werden soll. Der Benutzer soll eine Lösung eingeben, womit diese Activity beendet wird. Die aufrufende Activity bekommt die Information, ob die Aufgabe korrekt gelöst wurde und wertet diese aus. 35