11.09.2014
Author: Matija Paunovic

Wie können wir erkennen, ob eine Android Anwendung im Vordergrund oder Hintergrund läuft und warum sollte uns das interessieren?

Anders als bei iOS, laufen Android-Anwendungen im Hintergrund weiter, wenn der Benutzer zum Homescreen zurück wechselt. Beim letzten Android-Projekt an dem wir gearbeitet haben, haben wir deswegen einen zusätzlichen Authorisierungsschritt für den Fall benötigt, dass der Benutzer zur Anwendung zurückkehrt. Dies bedeutete, dass wir die Anwendungsstatus prüfen mussten (ist es minimiert oder nicht?). Außerdem durften wir nicht vergessen, denselben Authorisierungsschritt auch beim initialen Laden der Android-App anzuzeigen!

Batterie sparen durch clevere Nutzung des Android-Aktivitätslebenszyklus

Aber das ist noch nicht alles... Mit dieser Technik sind wir auch in der Lage, die Broadcast-Receiver zu steuern. Wenn der Benutzer die Anwendung minimiert, laufen die Broadcast-Receiver so lange weiter, bis das Android-Betriebssystem entscheidet, die App zu beenden. Überlicherweise wird eine Anwendung nur beendet, wenn die Systemressourcen anderweitig benötigt werden. So lange die Anwendung läuft, verbrauchen die Broadcast-Receiver weiterhin Strom und saugen so unnötig unseren Telefonakku leer!

Statische Attribute kommen uns zur Hilfe!

Eine von vielen Möglichkeiten, um zu erkennen, ob eine Anwendung minimiert ist, ist die Verwendung von statischen Attributen. Die Idee ist, ein statisches Attribut (integer) zu haben, welches hochgezählt wird, wenn eine Aktivität die „onStart()“-Methode aufruft. Dasselbe Feld wird heruntergezählt, wenn eine Aktivität die „onStop()“-Methode aufruft.

 

public class BaseActivity extends Activity
{
    /**
     * Counter which "memorizes" the application state.
     *
     *  0 = Application has been minimized.
     *  1 = Application has just started (or resumed).
     * 2+ = Application is running in foreground (activity change).
     */
    public static int activityCount = 0;
    
    /**
     * Run the jobs when the application has just started.
     */
    protected void runForegroundJobs()
    {
        Log.i("APPLICATION_STATE", "Application has started.");
    }
    
    /**
     * Run the jobs when the application has been minimized.
     */
    protected void runRunningInBackgroundJobs()
    {
        Log.i("APPLICATION_STATE", "Application is minimized.");
    }
    
    /**
     * Run the jobs in between the activities.
     */
    protected void runActivitySwitchJobs()
    {
        Log.i("APPLICATION_STATE", "Application has started new activity");
    }
    
    @Override
    protected void onStop()
    {
        super.onStop();
        activityCount--;
        
        // We have just "minimized" our application.
        if(activityCount == 0) {
            runRunningInBackgroundJobs();
        }
    }
    
    @Override
    protected void onStart()
    {
        super.onStart();
        activityCount++;
        
        // We have just resumed the application (or started it)
        if(activityCount == 1) {
            runForegroundJobs();
        // We have started another activity; the activityCount can become a
        // a number bigger than two (emulator) if you switch them really fast.
        } else if(activityCount > 1) {
            runActivitySwitchJobs();
        }
    }
}
 

Wie funktioniert das?

Wir sind abhängig von den Android-Aktivitätslebenszyklus-Eigenschaften. Immer wenn die App startet wird zuerst die Methode „onStart()“ aufgerufen. Wenn wir von einer Aktivität zu einer anderen wechseln, wird die Methode „onStart()“ vor der Methode „onStop()“ aufgerufen. Wenn also die zweite Aktivität geladen wird und die Zweite dadurch ersetzt, wird für die erste Aktivität die „onStop()“-Methode aufgerufen.

Somit haben wir drei Status:

  1. Wert "0". Die App ist minimiert.
  2. Wert "1". Die App läuft im Vordergrund. Entwerder weil sie gerade gestartet wurde, oder der Benutzer zu ihr zurückkehrt.
  3. Wert "2+" oder höher. Die App wechselt die Aktivitäten.Es ist möglich, dass der Wert größer als zwei wird, wenn der Benutzer die Aktivitäten sehr schnell zwischen den Aktivitäten hin und her wechselt (zum Beispiel durch einen Simulator)

Wenn der Benutzer den "Home"-Button drückt, ruft die Anwendung die "onStop()"-Methode auf. Da unser statisches Attribut nur den Wert 1 haben kann, wird die „onStop()“-Methode den Wert herunterzählen und den Wert des Attributs auf 0 setzen. Dadurch haben wir erkannt, dass die Anwendung minimiert wurde.

Wie implementiert man die BaseActivity im eigenen Projekt

Da unser Projekt Authorisierung in allen Aktivitäten benötigt, haben wir uns entschieden die Klasse „BaseActivity“ zu erstellen. Die Klasse enthält die Logik für die Erkennung der App-Minimierung. Unser Beispiel enthält auch Methoden, die die ganze Arbeit übernehmen, sobald der anvisierte Anwendungsstatus erkannt wurde.

Es liegt an Ihnen, wie Sie die Vererbung in Ihrem Projekt handhaben. Bei der Entwicklung von Javaanwendungen gibt es eine Sache, die Sie beachten sollten. Wegen des „Diamond-Problems“ ist es nur möglich, von einer Klasse zu erben. Im Gegensatz zu C++ erlaubt Java keine Mehrfachvererbung.

 

Diamond-Problem

 

 

Die Klassen Class2 und Class3 sind Subklassen von Class1. Nehmen wir an, dass Class4 eine Subklasse der beiden Klassen Class2 und Class3. Wenn man jetzt "Class4.onRun()" aufruft, welche Methode würde nun aufgerufen? Die "onRun()"-Methode von Class2 oder die "onRun()"-Methode von Class3? Das ist eine nicht eindeutige Abfrage.

C++ löst das Problem durch die Verwendung einer virtuellen Vererbung. In unserem Fall müssten wir die Klassen Class2 und Class3 als virtuelle Klassen definieren. C++stellt dann sicher, dass nur ein Subobjekt der Klasse 1 für jedes Class4-Objekt erzeugt wird.

Da wir Java verwenden und deswegen nicht die Möglichkeit haben an mehrere Klassen zu vererben, müssen wir unsere Vererbung verketten: