Android-Programmierung: Die Activity
Willemers Informatik-Ecke
Zurück zur Android-Hauptseite

Eine Activity verwaltet einen Bildschirm, also einen Dialog oder ein Formular. Bei Anlegen eines Projekts schlägt die IDE als erste Activity den Namen MainActivity vor. Diese Haupt-Activity wird automatisch im Manifest eingetragen und übernimmt die Steuerung des ersten Bildschirms.

Eine App wird über kurz oder lang aber mehrere Activities einsetzen wollen. Jede Activity muss im Manifest eingetragen werden.

Activity und Manifest

Eine Activity muss in der Datei AndroidManifest.xml eingetragen sein. Arbeitet man mit einer IDE, wird diese es automatisch erledigen, wenn man eine Activity als solche hinzufügt. Bei Android-Studio erreicht man dies über das Hauptmenü mit File|New|Actity| ....

Zustände einer Activity

Da die Activity einen Bildschirm und nicht die Anwendung repräsentiert, hat sie auch keine main-Funktion, sondern sie wird durch die App aufgerufen. Eine Activity kann entstehen, verschwinden, verdeckt werden, erzeugt oder gelöscht werden. Für jeden dieser Fälle kann sie sich informieren lassen, indem sie eine der folgenden Methoden implementiert:

void onCreate(Bundle bundle) und onDestroy()

Die Methode onCreate wird aufgerufen, wenn die Activity gerade erzeugt wurde. Diese Methode wird typischerweise für jede Activity überschrieben, schon um den Bildschirm zu initialisieren. Zuallererst mit super.onCreate(bundle) die Methode onCreate der Basisklasse aufgerufen.

Die Methode onDestroy() wird aufgerufen, wenn die App endgültig beendet wird. Sie entspricht also dem Gegenstück zu onCreate(), wird aber nicht immer verlässlich vor dem Ende der Activity aufgerufen.

Der Parameter Bundle

Der Parameter Bundle enthält den Zustand der Activity, den Sie eventuell bei einem zuvor unerwarteten Abbruch durch das Laufzeitsystem durch Überschreiben der Methode onSaveInstanceState noch gesichert haben. Den Sicherungsstatus Bundle können Sie aber auch durch Überschreiben der Methode void onRestoreInstanceState(Bundle bundle) erlangen.

Aufbau des Bildschirms

Im weiteren Verlauf von onCreate wird typischerweise die XML-Layout-Datei mit setContentView geladen.

void onStart()
Diese Methode wird aufgerufen, wenn die Activity sichtbar wird, typischerweise nachdem eine andere App gestoppt wurde. Sie erhält dabei nicht zwingend den Fokus.
void onStop()
Eine andere App wird aktiv. Die aktuelle App wird unsichtbar, aber nicht zerstört. Hier sollten alle Aktionen gestoppt werden, die für die Darstellung erforderlich sind, wie Animationen oder Aktualisierung der Oberfläche.

Es ist möglich, dass die Anwendung nach onStop ohne weitere Vorwarung vom Laufzeitsystem beendet werden kann.

void onRestart()
Die Activity wird wieder sichtbar. Aufruf erfolgt also vor jedem Aufruf von onStart, außer dem ersten.
void onPause()
Eine andere Activity - vermutlich von der eigenen App - kommt nach vorn. Die aktuelle Activity wird kurz angehalten. Der Code in der Methode sollte schlank gehalten werden, da das Ereignis oft auftreten kann.

Da in dieser Situation der Speicher für andere Apps freigegeben werden kann, sollte die App ihre Daten sichern und bei onResume wieder herstellen. Dies kann beispielsweise mit SharedPreferences erfolgen.

void onResume()
Eine pausierte Activity wird wieder in den Vordergrund geschoben und tritt mit dem Benutzer in Interaktion. Der Code in der Methode sollte schlank gehalten werden, da das Ereignis oft auftreten kann.

onResume muss die Daten wiederherstellen, die bei onPause gesichert wurden.

Zustand der Activity Anfang Ende
existent onCreate onDestroy
sichtbar onStart onStop
Im Vordergrund onResume onPause

void onSaveInstanceState(Bundle bundle) und void onRestoreInstanceState(Bundle bundle)

Die Methode onSaveInstanceState sollte der Zustand der Oberfläche in einem Objekt der Klasse Bundle speichern, die nach dem Ende der Activity in onRestoreInstanceState() wieder hergestellt werden kann. Die Methode onRestoreInstanceState() sollte die Oberfläche dann rekonstruieren.

Das Sichern und der Wiederaufbau des Bildschirms

Die App kann jederzeit vom System beendet werden, wenn beispielsweise der Speicher knapp wird. Das kann im Hintergrund geschehen. Der Anwender wird dennoch erwarten, dass er seine App in dem Zustand vorfindet, in dem er sie zuletzt gesehen hat.

Um diese Sicherung durchzuführen, überschreiben Sie onSaveInstanceState. Der Bundle-Parameter wird dort gefüllt.

@Override
public void onSaveInstanceState(Bundle saveInstanceState) {
    saveInstanceState.putBoolean("gesehen", entstanden);
    saveInstanceState.putString("name", name);
    // ...
    super.onSaveInstanceState(saveInstanceState);
}
Die Klasse Bundle stellt für die verschiedenen Typen jeweils eigene put- und get-Methoden zur Verfügung.

Der Bundle-Parameter kann später von onRestoreInstanceState() aber auch von onCreate wieder gelesen werden, um den Activity-Zustand zu rekonstruieren.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    if (savedInstanceState != null)
        if (savedInstanceState.containsKey("gesehen")) {
            entstanden = savedInstanceState.getBoolean("gesehen");
        }
        if (savedInstanceState.containsKey("name")) {
            name = savedInstanceState.getString("name");
        }
    }
}

Basisklasse Activity und AppCompatActivity

Diese Methoden werden von der Klasse Activity zur Verfügung gestellt. Die eigene Activity erweitert die Klasse Activity und überschreibt die gewünschten Methoden.

Wenn Android Studio eine Activity anlegt, erweitert diese AppCompatActivity. Damit erreicht es, dass die Activity auch zu älteren Android-Versionen kompatibel ist. Darum sollten Sie das auch machen.

package de.willemer.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
Der Aufruf setContentView führt dazu, dass die Layout-XML-Datei activity_main.xml entfaltet und dargestellt wird. In dieser XML-Datei wird das Layout und die Kontrollelemente der Activity definiert.

Activity und XML-Layout-Datei

Korrespondierend zu jeder Activity gibt es eine XML-Datei im Verzeichnis layout. Die IDE erzeugt im Allgemeinen sofort eine XML-Datei zur Activity. Bei der MainActivity heißt die passende Datei normalerweise activity_main.xml.

Im folgenden Listing wird beim Erzeugen der Activity mit der Funktion setContentView die XML-Datei als Basis für den eigenen Bildschirm herangezogen. Der Aufruf sorgt also für die Verbindung von XML-Datei und Activity.

import android.app.Activity;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         ...
}
Wird AppCompatActivity statt Activity erweitert, erhält die Activity eine App-Bar, also einen Balken, in dem sich auch ein Zugriff auf das Menü existiert. Dies ist für neuere Android-Versionen wichtig, weil dort oft bereits kein Standard-Button mehr für das Menü am Gerät existiert. Damit ist dann onOptionsItemSelected() für den Anwender nicht mehr erreichbar.

Wechsel der Activity

Um eine andere Activity zu starten, wird ein Intent erzeugt. Das Intent wird an die Methode startActivity() übergeben und damit die Ziel-Activity gestartet. Das Intent bestimmt also, welche Activity gestartet wird.

Das Intent wird über seinen Konstruktor mit zwei Activities gefüllt: Der aufrufenden Acitivity mit this und der Ziel-Activity, deren Klasse angegeben wird.

Intent intent = new Intent(this, AufgerufeneActivity.class);
startActivity(intent);

Activity bleibt auf dem Stack

Die aufrufende Activity läuft weiter, wartet also nicht auf das Ende der eben gestarteten Activity. Sie bleibt auf dem Activity-Stack.

Wird die gestartete Activity beendet, beispielsweise durch den Aufruf der Methode finish oder vom Benutzer durch Drücken der Back-Taste, erscheint die startende Activity wieder auf dem Bildschirm.

Datenübergabe bei Activity-Wechsel

Häufig müssen an die aufgerufene Activity Daten übermittelt werden. Diese können durch den Aufruf von putExtra im Intent der Ziel-Activity hinterlegt werden. Dazu wird ein Schlüssel verwendet, damit bei mehreren Daten der richtige Wert ermittelt werden kann.
Intent intent = new Intent(this, AufgerufeneActivity.class);
// Intent mit den Daten füllen
intent.putExtra("key1", "Irgendwelcher Text");
intent.putExtra("key2", "Nochson Text");
startActivity(intent);
Die mit putExtra gesendeten Daten werden mit getStringExtra empfangen. Dabei wird der erste Parameter als Schlüssel verwendet.
...
public void onCreate(Bundle bundle) {
    ...
    Intent intent = getIntent();
    String data = intent.getStringExtra("key1");
    String andere = intent.getStringExtra("key2");
    ...
}
Um eigene Objekte zu übertragen, müssen diese Parcelable implementieren. Dann wird mit den Methoden putExtra("key", object) geschrieben und mit getParcelableExtra("key") zurückgeholt.

Die aufgerufene Activity schließt sich nach dem Start der anderen Activity durch den Aufruf von finish();.

Aufruf einer Sub-Activity

Nach einem startActivity-Aufruf wird die neue Activity gestartet, aber die aufrufende Activity nicht blockiert. Sie wartet also nicht auf die Ergebnisse der Activity.

Ist sie aber an den Ergebnissen einer Activity interessiert, muss sie sie als Sub-Activity aufrufen. Dazu ruft sie die Methode startActivityForResult.

int SUB_ACT_HOLEADRESSE = 4711;
Intent intent = new Intent(this, ZielActivity.class);
startActivityForResult(intent, SUB_ACT_HOLEADRESSE);
Die aufgerufene Sub-Activity muss ihre Ergebnisse für den Aufrufer über die Methode setResult hinterlegen. Als Parameter wird der Status und ein Intent verwendet.
Uri uriGast = Uri.parse("content://gast/" + gastId);
Intent intent = new Intent(Intent.ACTION_PICK, uriGast);
setResult(RESULT_OK, intent);
finish();
Mögliche Stati von setResult: Die aufrufende Activity überschreibt die Methode onActivityResult.
@Override
public void onActivityResult(int request, int result, Intent intent) {
     super.onActivityResult(requestCode, resultCode, intent);

    // request: die Anfrage
    // result: typischerweise eine Activity.RESULT-Konstante
    // intent: liefert die zurückgegegebenen Daten über intent.getData()
}

Links