Android: Unterschied zwischen den Versionen

Aus m-wiki
Zur Navigation springen Zur Suche springen
Zeile 156: Zeile 156:
* behandelt "Events" (z. B. Klick auf einen Button)
* behandelt "Events" (z. B. Klick auf einen Button)
* benutzt "Intents", um andere Activities zu starten
* benutzt "Intents", um andere Activities zu starten
== Fragment ==
Wurden mit Android 3.1 eingeführt und sind selbständige Teilbereiche einer Activity. Können entsprechend auf verschiedenen Activities wiederverwendet oder in einer Activity mehrfach eingesetzt werden.


== View ==
== View ==

Version vom 17. November 2020, 00:44 Uhr

Einführung

  • Fast alle Java-Klassen stehen zur Verfügung plus Verschlüsselung, HTTP, JSON, XML Bibliotheken
  • Für die Programmierung steht in neueren Versionen Kotlin zur Verfügung.
  • Keine main()-Funktion - stattdessen: lose gekoppelte Komponenten, eine oder mehrere davon als Einstiegspunkt definierbar
  • Wichtigste Komponente: "Activity" - entspricht einem sichtbaren Fenster auf dem Screen (Ähnlich wie Tabs eines Browsers). Man kann etwa ein Programm mit Screen 1 (Hauptseite) aufrufen oder direkt Screen 2 (Unterseite). Der Aufruf geschieht über die App-Icons.

Entwicklungsumgebung

Zum konkreten Einrichten siehe das Buch Android Apps programmieren). Kapitel 2.1.1 Installation.

Neues Projekt

Mit dem Assistenten wird ein neues Projekt erstellt:
Wähle "File" → "New" → "Project..."; im "New Project"-Dialog wähle "Android Project" aus dem "Android" Order.

Füll den "New Android Project"-Dialog wie folgt aus:

  • Project name: "Hello Workshop"
  • Verwende die "default location" oder lege eine andere Location fest
  • Build target: Android 1.6 (für Kompatibilität mit älteren Versionen kann man später noch schauen)
  • Application name: "Hello Workshop"
  • Package name: "de.test.hello"
  • Create Activity: "HelloWorkshopActivity"
  • Min SDK Version: "4"

Klicke auf den "Finish"-Button.

Im Android-Buch hat es eine neuere bebilderte Anleitung.

Emulator

Falls kein Andoid-Gerät vorhanden ist, oder das gewünschte Gerät fehlt.

Klicke auf das "Android SDK and AVD manager"-Icon in der Icon-Leiste von Eclipse. Klicke auf "New" Im "Create new AVD"-Dialog, gib folgendes ein:

  • Name: "G1"
  • Target: "Android 1.6 - API Level 4"
  • SD Card Size: "1024" MiB
  • Skin: Built-in: "Default (HVGA)"

Dann klicke auf "Create AVD" (kann eine Weile - bis zu einigen Minuten - dauern)

Verwendete Dateien

Um die verwendeten Dateien zu sehen, muss man den Navigator einblenden, der auf der linken Seite zusammengeklappt werden kann. Anschliessend muss man dann oberhalb der Ansicht unterhalb vom Projektnamen die Art der Darstellung wählen. Falls man mehrere Projekte offen hat, zum gewünschten Projekt navigieren.

Bei der Ansicht Android wird das Projekt "logisch" aufgelistet und entsprechend Dateien, die zusammengehören, wie etwa die Ressourcen zusammen aufgeführt.
Will man hingegen die wirkliche Datenstruktur sehen, so wechselt man auf Project Files, welches den Baum auflistet.
Die Projekte werden standardmässig unter folgendem Pfad gespeichert:
C:\Users\<Benutzername>\AndroidStudioProjects\<Projektname>

Die folgende Tabelle gibt den Stand von Nov. 2020 mit Android Studio 4.1 wieder. Die Entwicklung ist dynamisch und daher kann es gut sein, dass Dateien immer noch verschoben werden und auch Verzeichnisse anders aufgebaut werden. Entsprechend muss man manche Dateien halt suchen, wenn sie nicht am entsprechenden Ort gefunden werden können oder man schaut im Studio, wohin referenziert wird.
Da im Projekt sehr viele Dateien involviert sind, werden "interne" Verzeichnisse und Dateien wie etwa die diversen Build- und Testverzeichnisse nicht aufgeführt. Auch Verzeichnisse, welche nur für die Versionsverwaltung oder fürs Kompilieren verwendet werden, werden nicht aufgelistet.

Datei/Ordner Beschreibung
/app Ordner in dem sich das aktuelle Modul befindet. Bei grösseren Projekten können mehrere Module definiert werden.
/app/src Source-Ordner aller Klassen des Moduls
/app/src/main/AndroidManifest.xml Linked alle wichtigen Dateien des Projekts. Dort werden auch die Berechtigungen fürs Projekt angemeldet (Datei- und Internetzugriff usw.). Dazu muss man dort Services anmelden oder wenn man ContentProvider für externe Apps bereitstellt.
/app/src/main/java/<domain>/<projektname>/MainActivity.java Klasse der Haupt-Activity. Verweist mit setContentView(R.layout.main); auf das Layout, welches in der main.xml definiert wurde.
/app/src/main/res Layout- Sprach- und Bilddateien.
/app/src/main/res/drawable Bilddateien. Diese werden in den entsprechenden Unterordnern auflösungsabhängig gespeichert, damit die App auch bei unterschiedlichen Geräten in etwa gleich ausschaut.
/app/src/main/res/layout Layouts. Da das Layout beim drehen meist etwas anders angezeigt wird, gibt es auch den Ordner layout-land, in dem das "landscape" Layout abgelegt wird.
/app/src/main/res/layout/activity_main.xml Das Layout wird als XML-Datei erstellt. Die Ressourcen werden dort entsprechend auf die Text-Ressource-Dateien verwiesen, damit man die App nur einmal kompilieren muss und trotzdem verschiedene Sprachen anbieten kann. Wird erstellt aus dem Namen, den man beim generieren des Projekts für das Layout wählt. Ohne Anpassung wird er aus dem Projektnamen gebildet.
/app/src/main/res/menu Falls man ein Menü in der Action-Bar anbieten will, werden die Ressourcen dafür hier angelegt. Standardmässig wird das Manü aber nicht angelegt.
/app/src/main/res/mipmap* Icons. Diese werden in den entsprechenden Unterordnern auflösungsabhängig gespeichert, damit diese auch bei unterschiedlichen Geräten in etwa gleich ausschauen. (xxxhdpi = 192 x 192 Pixel – 640 dpi / xxhdpi = 144 x 144 Pixel – 480 dpi / xhdpi = 96 x 96 Pixel – 320 dpi / hdpi = 72 x 72 Pixel – 240 dpi / mdpi = 48 x 48 Pixel – 160 dpi / ldpi = 36 x 36 Pixel – 120 dpi)
/app/src/main/res/values(-xx) Text-Ressource-Dateien. Diese Dateien enthalten Wertepaare für verschiedene Anwendungen wie Farben oder Strings, welche man dann in verschiedene Sprachen überstzene kann und die dann das entsprechende Länderkürzel angehängt bekommen.
/assets Ordner für Binär-Dateien (alles, was Android nicht selbst verwaltet). Wird standardmässig nicht angelegt.
/gradle Wird für die Versionsverwaltung eingesetzt.

AndroidManifest.xml

Legt diverse Werte zum Aussehen und Verhalten des Programms fest. https://developer.android.com/guide/topics/manifest/manifest-intro

Folgende Einträge sind für die Unterstützung von unterschiedlichen Geräte möglich. Evtl. bei neueren Versionen nicht mehr notwendig.

<supports-screens android:anyDensity="true"
                  android:largeScreens="true" 
                  android:smallScreens="true" />
  • anyDensity für hohe Auflösungen
  • largeScreens bei grossen Displays
  • smallScreens für kleine Displays

Für Berechtigungen werden Einträge in folgender Weise hinzugefügt:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />

Wenn man Eclipse verwendet, kann man aus den Warnungen ableiten, wenn man etwas falsch definiert. Dazu kann man entweder die Datei direkt bearbeiten oder dies über den Tab umstellen und manches direkt grafisch anpassen.

Ein Beispiel ist im Android-Buch auf Seite 39 (Kap. 2.2.2 App-Bausteine) aufgeführt.

MainActivity.java

Enthält, wie unter Programmierung gezeigt, das Hauptprogramm. Der Name wird entsprechend bei Projekteröffnung festgelegt. Hier werden unter anderem die Elemente definiert.

private Button hiButton; private Button helloButton;

strings.xml

Legt die Werte für die Strings fest. Hier wurden zwei Srings "hello" und "app_name" definiert, welche nun in anderen Dateien verwendet werden können (Layout oder Programm).

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, HelloWorkshopActivity!</string>
    <string name="app_name">Hello Workshop</string>
</resources>

Android-App kompilieren (Gradle)

Im Gegensatz zu einem "normalen" Programm, müssen bei einer Android-App viele verschiedene Tools zusammenarbeiten, um am Schluss eine lauffähige App bereitstellen zu können. Gradle ist ein Build Management Tool für Java, das diese Aufgaben bündelt.

  1. Herunterladen von externen Abhängigkeiten (externe Bibliotheken)
  2. Kompilieren der Java-Dateien in DEX
  3. Kompilieren der Ressourcen (Bilder, Icons, usw.)
  4. Verpacken als APK-Datei (DEX + Ressourcen)
  5. Signieren der APK-Datei
  6. Optimieren der App auf Speicherverbrauch

Gradle benutzt eine auf Groovy aufbauende DSL (Domain Specific Language). Wenn man weiss wie und es braucht, so kann man den Build-Prozess entsprechend anpassen. Siehe dazu den Link: https://developer.android.com/studio/build

Für die Einbindung der externen Bibliotheken wird das Maven-Repository eingebunden.

Programmierung

Zuerst ein Beispiel, welches unten erklärt wird:

class MyActivity extends Activity {

  onCreate {
    View view = ... // erstellt den sichtbaren Teil
    setContentView(view);
    ...
  } // end Eventhandler onCreate

  onClick {
    ...
    Intent intent = ... // Zugriff auf externes Programm
    startActivity (intent);
  } // end Eventhandler onClick

} // end class MyActivity

Activity

  • definiert eine "View", zur Anzeige auf dem Screen. Entspricht einem Fenster.
  • behandelt "Events" (z. B. Klick auf einen Button)
  • benutzt "Intents", um andere Activities zu starten

Fragment

Wurden mit Android 3.1 eingeführt und sind selbständige Teilbereiche einer Activity. Können entsprechend auf verschiedenen Activities wiederverwendet oder in einer Activity mehrfach eingesetzt werden.

View

  • eine "View" ist der sichtbare Teil der Activity
  • definiert in einer XML-Layout-Datei (oder im Code)

Events / Programmablauf

  • werden ausgelöst, wenn etwas geschieht (z. B ein Button geklickt wird)
  • ruft eine Listener-Methode auf, sofern ein Listener definiert ist

Ein Beispiel mit mehreren Events für einen Programmablauf sieht man hier: http://www.androidpit.de/de/android/wiki/view/Datei:Beginners_Workshop_Activity_LC.png
Um Datenverlust oder den Verlust des Zustands einer Activity zu vermeiden, müssen die Daten/der Zustand der Activity gesichert werden, wenn diese pausiert (nicht mehr im Vordergrund, aber noch sichtbar) oder gestoppt (nicht mehr sichtbar) wird.

onClick()

  • Aufruf beim Drücken auf einen Button
EditText nameField = (EditText) findViewById(R.id.name_field);
String name = nameField.getText().toString();
if (name.length() == 0) {
    new AlertDialog.Builder(this) 
                   .setMessage(R.string.error_name_missing)
                   .setNeutralButton(R.string.error_ok, null)
                   .show();
    return;
} // end if

onCreate()

  • wird einmalig beim Programmstart aufgerufen
  • muss die View und die Elemente darin definieren
  • springt anschliessend weiter nach onStart()
  • definiert die Listener-Aufrufe
hiButton = (Button)findViewById(R.id.hi_button);
hiButton.setOnClickListener(this);
helloButton = (Button)findViewById(R.id.hello_button);
helloButton.setOnClickListener(this);

onDestroy()

  • Wird nur aufgerufen, wenn das Programm explizit beendet wird

onPause()

  • Geht weiter nach onResume, wenn es wieder in den Vordergrund geholt wird oder nach onStop, wenn es gar nicht mehr sichtbar ist
  • Da das Programm bei Speichermangel in diesem Zustand "abgeschossen" werden kann, müssen spätestens hier die Benutzerdaten gesichert werden

onRestart()

  • Falls das Programm gestoppt wurde, doch noch nicht wegen Speichermangels aus dem RAM entfernt wurde und nun wieder in den Vordergrund kommt, wird diese Methode aufgerufen
  • Springt anschliessend direkt nach onStart()

onResume()

  • Wird jedes Mal aufgerufen, wenn die App nach einer Pause (wieder) in den Vordergrund kommt

onStart()

  • Springt weiter nach onResume()

onStop()

  • Wird aufgerufen, wenn das Programm nicht mehr sichtbar ist
  • Je nach weiterer Folge, geht der Programmlauf weiter mit onDestroy oder onRestart.

Intent

  • startet eine andere Activity ("öffnet ein neues Fenster")
  • kann Daten an die zu startende Activity übergeben
  • kann Activities aus anderen Apps starten!

Layouts und Elemente

Wie oberhalb erwähnt, wird in /res/layout/main.xml das Layout der Hauptdatei festgelegt. Das heisst, hier werden die Elemente festgelegt.

vertikale und horizontale Layouts

Layouts können auch geschachtelt werden. Das Hauptlayout ist meist vertikal.

Vertikales Layout mit einem Titel:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
>
  <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
  />
</LinearLayout>

Der Inhalt des Strings wird in der /res/layout/strings.xml definiert

Horizontales Layout mit zwei Knöpfen.

<LinearLayout 
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
     >
    <Button 
        android:id="@+id/hi_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/hi_button" 
        />
    <Button 
        android:id="@+id/hello_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/hello_button" 
        />
</LinearLayout>

TextView (Label)

<TextView
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_marginTop="20dp"
    android:text="@string/enter_your_name"
/>

Hier müssten wir noch den String "enter_your_name" in der strings.xml definieren.

EditText (Eingabefeld)

<EditText
    android:id="@+id/name_field"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
/>

Hier bekommt das Feld eine id("name_field"), welche man später im Programm verwenden kann, um den Wert auszulesen.

Button (Knopf)

<Button 
    android:id="@+id/hi_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:text="@string/hi_button" 
/>

Der Knopf braucht neben der Beschriftung, welche in der strings.xml definiert wird, noch eine id, welche wieder im Programm über ein Event ausgewertet werden kann.

Programmierbeispiel komplett

Wenn man ein Android-Projekt unter Eclipse erstellt, so generiert Eclipse mehrere Dateien. Hier werden nun alphabetisch alle Dateien aufgeführt, welche im Beispielprojekt manuell angepasst wurden.

AndroidManifest.xml

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

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    
    <supports-screens 
        android:anyDensity="true"
        android:largeScreens="true" 
        android:smallScreens="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.helloworkshop.HelloWorkshopActivity"
            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>

HelloWorkshopActivity.java

package com.example.helloworkshop;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;


public class HelloWorkshopActivity extends Activity implements OnClickListener {

	private Button hiButton;
	private Button helloButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        hiButton = (Button)findViewById(R.id.hi_button);
        hiButton.setOnClickListener(this);
        
        helloButton = (Button)findViewById(R.id.hello_button);
        helloButton.setOnClickListener(this);
    } // end onCreate

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.hello_workshop, menu);
        return true;
    } // end onCreateOptionsMenu

    public void onClick(View v) {
        EditText nameField = (EditText) findViewById(R.id.name_field);

        String name = nameField.getText().toString();

        if (name.length() == 0) {
            new AlertDialog.Builder(this).setMessage(
                    R.string.error_name_missing).setNeutralButton(
                    R.string.error_ok,
                    null).show();
            return;
        }

        if (v == hiButton || v == helloButton) {
            int resourceId = v == hiButton ? R.string.hi_greeting
                    : R.string.hello_greeting;

            String greeting = getResources().getString(resourceId, name);
            Toast.makeText(this, greeting, Toast.LENGTH_LONG).show();

            TextView greetingField = (TextView) findViewById(R.id.greeting_field);
            greetingField.setText(greeting);
        }
    } // end onClick
    
} // end class HelloWorkshopActivity

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

	<TextView  
    	android:id="@+id/greeting_field"
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="@string/hello"
	/>

	<TextView 
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:layout_marginTop="20dp"
	    android:text="@string/enter_your_name"
    />
	
	<EditText
	    android:id="@+id/name_field"
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	>
	</EditText>
	
	<LinearLayout 
	    android:orientation="horizontal"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
     >
	    <Button 
	        android:id="@+id/hi_button"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="@string/hi_button" 
	    />
	    <Button 
	        android:id="@+id/hello_button"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="@string/hello_button" 
	    />
	</LinearLayout>

</LinearLayout>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="action_settings">Settings</string>
    <string name="app_name">Hello Workshop</string>
    <string name="enter_your_name">Gib bitte Deinen Namen ein:</string>
    <string name="error_name_missing">Please enter your name.</string>
    <string name="error_ok">OK</string>
    <string name="hello">Hallo Welt Workshop!</string>
    <string name="hello_button">Say Hello!</string>
    <string name="hello_greeting">Hello %s!</string>
    <string name="hi_button">Say Hi!</string>
    <string name="hi_greeting">Hi %s!</string>
</resources>

Programm auf Gerät verschieben

Mittels Google-Konto

  1. Im Ordner bin/res befindet sich die Datei "Projektname.apk". Diese ist die notwendige Datei.
  2. Die Datei als Anhnag ans Google-Konto senden
  3. Den Anhang im Gerät anwählen und danach installieren. Will das Gerät dies nicht, kann evtl. das Programm AKPatcher verwendet werden (hat bei mir aber immer nur den Info-Screen angezeigt)
  4. Anschliessend kann die App übers App-Menü gestartet werden

Mittels USB-Verbindung

Folgende Bildergalerie verwenden: http://www.chip.de/bildergalerie/So-geht-s-APKs-via-USB-installieren-Galerie_56637615.html

  1. Einstellung: Unbekannte Quellen zulassen
  2. Verbinden im Massenspeicher Modus
  3. APK-Datei auf das Gerät in den gewünschten Ordner kopieren
  4. Mit dem Dateimanager ins obige Verzeichnis navigieren und die Datei anwählen und installieren

Links

Link Beschreibung Niveau
Java Java-Wiki Anfänger
http://www.vogella.com/articles/Android/article.html Android-Einführungstutorial englisch Anfänger-Fortgeschrittene
http://www.makeuseof.com/tag/write-google-android-application/ Android erste Applikation von Google englisch Anfänger
http://www.kammerath.net/android-app-programmieren.html Android app programmieren deutsch Anfänger
http://www.vogella.com/articles/AndroidIntent/article.html Android Intents englisch Fortgeschrittene