Android Threading Tutorial und Beispiele

Dies ist unser Android-Threading-Tutorial. Wir untersuchen, was ein Thread ist und stellen verschiedene Abstraktionen für die Thread Klasse vor.

Was ist ein Thread?

Ein Thread ist ein Ausführungspfad, der innerhalb eines Prozesses existiert.

Ein Prozess kann einen oder mehrere Threads haben.

Ein "single-threaded " Prozess hat einen "Thread", während ein "multi-threaded " Prozess mehr als einen "Thread" hat.

Bei einem "Single-Thread"-Prozess gibt es nur einen Fluss der Ausführung von Anweisungen, während bei einem "Multi-Thread"-Prozess mehrere Sätze von Anweisungen gleichzeitig ausgeführt werden.

Ein "Multi-Thread"-Prozess hat Teile, die gleichzeitig laufen, und jeder Teil kann eine bestimmte Aufgabe unabhängig ausführen.

Multi-Threading" ist also ein Mechanismus, der es uns ermöglicht, Programme so zu schreiben, dass mehrere Aktivitäten gleichzeitig in demselben Programm ablaufen können.

Vor allem in der heutigen Umgebung mit Multicore-Geräten sollten Entwickler in der Lage sein, gleichzeitige Ausführungsstränge zu erstellen, die Daten aus mehreren Ressourcen kombinieren und aggregieren.

Es ist aber auch wichtig zu wissen, dass ein System, das nur über einen einzigen Ausführungskern verfügt, in Wirklichkeit die Illusion einer gleichzeitigen Ausführung erzeugen kann. Dies geschieht, indem die verschiedenen "Threads" ineinander verschachtelt ausgeführt werden.
Aber es tut dies so schnell, dass wir denken, dass es die Aufgaben tatsächlich gleichzeitig ausführt.

Der Haupt-Thread

Wenn Sie Ihr Projekt starten, wird normalerweise Ihr application Prozess beginnen. Zuerst gibt es Haushalts-Threads für die Android Runtime oder Dalvik Virtual Machine.

Abgesehen davon erstellt das Android-System einen "Thread" für die Ausführung mit dem Namen "Main". Dies wird der Hauptthread für Ihre Anwendung sein.

Dieser Thread wird manchmal auch UI Thread`` genannt.

Deine Anwendung kann viele andere Threads haben, die normalerweise Hintergrundthreads genannt werden. Der Haupt-Thread ist jedoch der wichtigste. Dieser Thread ist für die Interaktion mit Android-Komponenten und Ansichten verantwortlich. Er rendert sie und aktualisiert auch ihren Status.

Dieser Thread ist sehr wichtig, vor allem angesichts der Tatsache, dass hier alle Android-Komponenten (Activity, Services, BroadcastReceiver ) standardmäßig ausgeführt werden.

Dieser Thread ist für die Verarbeitung von Benutzereingabe-Ereignissen zuständig und hört auf diese. Da er so wichtig ist, ist es immer ratsam, ihn ansprechbar zu halten, indem man:

  1. Keine Aufgaben, die wahrscheinlich viel Zeit in Anspruch nehmen, wie z.B. Eingabe/Ausgabe (I/O) in diesem Thread. Diese Aufgaben können den Haupt-Thread für eine unbestimmte Zeit blockieren und müssen daher in einen Hintergrund-Thread ausgelagert werden.
  2. Keine CPU-intensiven Aufgaben in diesem Thread ausführen. Wenn Sie einige teure Berechnungen oder Aufgaben wie Videokodierung haben, müssen Sie diese ebenfalls in einen Hintergrundthread auslagern.

Dieser Thread hat normalerweise eine Einrichtung, die Looper genannt wird. Looper" wird eine MessageQueue enthalten. Eine MessageQueue ist einfach eine Warteschlange von Nachrichten mit einer Arbeitseinheit, die sequentiell ausgeführt werden sollen.

Wenn also eine Nachricht bereit ist, in der Warteschlange verarbeitet zu werden, wird der Looper Thread diese Nachricht aus der Warteschlange holen. Diese Nachricht wird synchron (sequentiell) an den Ziel-Handler weitergeleitet. Dieser Handler ist bereits in der Nachricht angegeben.

Dann beginnt der Handler mit seiner Arbeit und erledigt sie. Wenn er seine Arbeit beendet hat, beginnt der "Looper"-Thread mit der Verarbeitung der nächsten in der Warteschlange verfügbaren Nachricht und leitet sie weiter, damit sie ebenfalls ausgeführt wird.

Wie Sie sehen, ist dieser Prozess sequentiell. Nehmen wir also an, dass unser Handler seine Arbeit nicht schnell beendet, wird der Looper nur darauf warten, andere anstehende Nachrichten in der Warteschlange zu verarbeiten.

In diesem Fall zeigt das System den Dialog "Application Not Responding (ANR)" an. Sie haben dies vielleicht schon in einigen Anwendungen gesehen. Es bedeutet, dass die Anwendung nicht auf Benutzereingaben reagiert. Sie ist jedoch mit ihrer Arbeit beschäftigt.

Der ANR-Dialog wird den Benutzern angezeigt, wenn eine Anwendung nicht innerhalb von fünf Sekunden auf Benutzereingaben antwortet. Das System bietet den Benutzern dann die Möglichkeit, die Anwendung zu beenden.

Sie werden auf diese Art von Szenario stoßen, wenn Sie versuchen, intensive Aufgaben in Ihrem Haupt-"Thread" zu erledigen. Das heißt, wenn Sie zum Beispiel versuchen, in Ihrem Haupt-Thread Folgendes zu tun:

  1. Zugriff auf das Netzwerk/Webdienste/Internet
  2. Zugriff auf Dateisystem-Ressourcen.
  3. Versuchen Sie, große Datenmengen zu verarbeiten oder komplexe mathematische Berechnungen durchzuführen usw.

Der meiste Code, den Sie schreiben, wie z.B. in Ihren Aktivitäten, Fragmenten und Diensten, wird normalerweise standardmäßig im Haupt-Thread ausgeführt, es sei denn, Sie erstellen ausdrücklich einen Hintergrund-Thread.

Android SDK basiert auf einer Teilmenge des Java SDK. Java SDK ist vom "Apache Harmony"-Projekt abgeleitet und bietet Zugang zu Low-Level-Concurrency-Konstrukten wie:

  1. java.lang.Thread".
  2. java.lang.Runnable`.
  3. Schlüsselwörter synchronized und volatile.

Thread Klasse

Die Klasse java.lang.Thread ist das grundlegendste Konstrukt, um Threads zu erstellen.

Sie ist auch die am häufigsten verwendete. Diese Klasse erzeugt eine neue unabhängige Ausführungslinie in einem Java-Programm.

Eine Möglichkeit, einen neuen Thread zu erstellen, ist die Unterklassifizierung oder Erweiterung der Klasse java.lang.Thread.

public class MyThread extends Thread {
    public void run() {
        Log.d("Generic", "Our thread is running ...");
    }
}

Wir können dann unsere Hintergrundaufgabe innerhalb der Methode run() ausführen.

Allerdings ist dieser Thread noch nicht gestartet. Dazu müssen wir diese Klasse instanziieren und unseren Thread explizit starten:

    MyThread myThread = new MyThread();
    myTread.start();

Die Methode start() befindet sich in der Klasse Thread. Ihr Aufruf weist das System an, einen Thread innerhalb des Prozesses zu erstellen und führt die
Methode run() aus. Die run() Methode wird automatisch ausgeführt, wenn wir die start() Methode aufrufen.

Allgemeine Threading Methoden

(a). Thread.currentThread()

Diese Methode gibt den Thread des Aufrufers zurück, d.h. den aktuellen Thread.

(b). Thread.sleep(time)`

Diese Methode veranlasst den Thread, der diese Nachricht gesendet hat, für die angegebene Zeitspanne (angegeben in Millisekunden und Nanosekunden) zu schlafen. Die Genauigkeit ist nicht garantiert - der Thread kann mehr oder weniger schlafen als gefordert.

Grundsätzlich hält es den aktuellen Thread von der Ausführung für die
angegebene Zeitspanne.

(c). getContextClassLoader()

Diese Methode gibt den Kontext ClassLoader für diesen Thread zurück.

(d). Start()

Diese Methode startet den neuen Thread der Ausführung. Die Methode run() des Empfängers wird vom Empfänger-Thread selbst aufgerufen (und nicht vom Thread, der start() aufruft).

(e). Thread.getName() und Thread.getId()

Diese ermitteln den Name bzw. die TID. Sie werden hauptsächlich für Debugging-Zwecke verwendet.

(f) Thread.isAlive()

isAlive() prüft, ob der Thread gerade läuft oder ob er
seine Arbeit bereits beendet hat.

(g) Thread.join()

join() blockiert den aktuellen Thread und wartet, bis der angesprochene
Thread seine Ausführung beendet hat oder stirbt.

Wie man die Reaktionsfähigkeit einer Anwendung aufrechterhält

Der beste Weg, die Reaktionsfähigkeit einer Anwendung aufrechtzuerhalten, besteht nicht darin, langwierige Operationen zu meiden. Stattdessen werden sie vom Hauptthread ausgelagert
Thread ausgelagert werden, so dass sie im Hintergrund von einem anderen Thread bearbeitet werden können.

Der Hauptthread kann dann weiterhin reibungslos Aktualisierungen der Benutzeroberfläche verarbeiten und zeitnah auf Benutzerinteraktionen reagieren.

Normalerweise gibt es eine Reihe typischer Vorgänge, die in vielen Anwendungen vorkommen und nicht nur viel Zeit, sondern auch Geräteressourcen verbrauchen.

Dazu gehören:

  • Zugriff auf und Kommunikation über das Netzwerk, insbesondere das Internet.
  • Dateieingabe- und -ausgabeoperationen. Diese finden auf dem lokalen Dateisystem statt.
  • Verarbeitung von Bildern und Videos.
  • Komplexe mathematische Berechnungen.
  • Textverarbeitung - Versuch der Verarbeitung oder Analyse eines großen Textblocks.
  • Datenkodierung und -dekodierung.

Schnelle Threading Beispiele

1. Erstellen eines einfachen Timers mit der Thread Klasse

Dies ist eine Klasse, die zeigt, wie man einen einfachen Timer implementiert. Sie gibt nichts aus und ist nur eine Klasse, die zeigt, wie man eine solche Idee implementieren kann.

import java.lang.Thread;

public class TimerClass extends Thread{

    boolean timeExpired;
    double mTime;
    /** Creates a new instance of TimerClass */
    public TimerClass(double time){
        mTime = time;
    }

    public void run(){

        timeExpired = true;
        mTime = mTime * 1000;
        double startTime = System.currentTimeMillis();
        double stopTime = startTime + mTime;
        while(System.currentTimeMillis() < stopTime && timeExpired == false){
              try {
                Thread.sleep(10);
            } catch (InterruptedException e){ }
        }

        timeExpired = true;

    }

    public boolean getTimeExpired(){
        return true;
    }

    public void cancel(){
        timeExpired = true;
    }

}

2. Vollständig wiederverwendbare Thread Utility Klasse

import android.os.Looper;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Threading tools
 * </p>
 */
public class ThreadUtils {

    private final static ExecutorService sThreadPool = Executors.newCachedThreadPool();

    /**
     * Current thread
     */
    public static Thread currentThread() {
        return Thread.currentThread();
    }

    /**
     * Current process ID
     */
    public static long currentThreadId() {
        return Thread.currentThread().getId();
    }

    /**
     * Current process name
     */
    public static String currentThreadName() {
        return Thread.currentThread().getName();
    }

    /**
     * Determine if it is a UI thread
     */
    public static boolean isUiThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    /**
     * Runs on the UI thread
     */
    public static void runOnUiThread(Runnable action) {
        if (action == null) {
            return;
        }
        if (Looper.myLooper() == Looper.getMainLooper()) {
            action.run();
        } else {
            HandlerUtils.uiPost(action);
        }
    }

    /**
     * Runs in the background thread
     */
    public static void runOnBackgroundThread(Runnable action) {
        if(action==null){
            return;
        }
        if (Looper.myLooper() != Looper.getMainLooper()) {
            action.run();
        }else{
            sThreadPool.submit(action);
        }
    }

    /**
     * Run on asynchronous thread
     */
    public static void runOnAsyncThread(Runnable action) {
        if (action == null) {
            return;
        }
        sThreadPool.submit(action);
    }

    /**
     * Runs on the current thread
     */
    public static void runOnPostThread(Runnable action) {
        if(action==null){
            return;
        }
        action.run();
    }

    public static void backgroundToUi ( final Runnable background , final Runnable ui ) {
        runOnBackgroundThread(new Runnable() {
            @Override
            public void run() {
                background.run();
                runOnUiThread ( ui );
            }
        });
    }
}

Categorized in:

Tagged in: