Android - Threads: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 1: Zeile 1:
 
 
== Links ==
 
== Links ==
 
* http://openbook.galileocomputing.de/javainsel9/javainsel_14_002.htm#mj45ef6b526108a654e748170e45b47506
 
* http://openbook.galileocomputing.de/javainsel9/javainsel_14_002.htm#mj45ef6b526108a654e748170e45b47506
 
* http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html#androidbackground (gute Artikel Reihe)
 
* http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html#androidbackground (gute Artikel Reihe)
  
== Allgemein ==
+
== Einführung ==
 +
=== UI-Thread und Hintergrund Threads ===
 +
* Jede App läuft in einem eigenen Prozess mit eigener Dalvik Virtual Machine. Für die Sichtbaren Bestandteile der App ist ein '''User-Interface-Thread''' zuständig. Die Start-Activity läuft in diesem UI-Thread.
 +
* Aufwändige Berechnungen '''frieren deshalb das UI ein'''. Wenn der Thread zu lange "weg" und nicht auf Benutzereingaben reagieren kann, wird er von Android gekillt (Application Not Responding - ANR.
 +
* Threads sind problemlos möglich aber Zugriff auf '''Views''' nur über den '''UI-Thread''' Möglich.
 +
-> Kommunikation zwischen Hintergrund-Thread und UI-Thread notwendig.
 +
 
 +
=== Typisches Beispiel ===
 +
* Button Click führt zu langer Berechnung
 +
* Berechnung im Hintergrund-Thread
 +
* Anzeige des Ergebnisses in TextView
 +
-> Problem '''Anzeige''' geht nur über UI-Thread, '''Berechnung''' geht nur über Hintergrund Thread, UI soll nach Berechnung sofort Ergebnis anzeigen.
 +
 
 +
Man braucht also etwas was es ermöglicht Threads vom Haupthread zu starten und das Ergebnis zurück zu schicken.
 +
=== Lösung Callback für Threads ===
 +
==== Runnable ====
 +
Objekte die etwas ausführen können
 +
==== Message ====
 +
Container für Daten (z.B. Bundle)
 +
==== Handler ====
 +
* Ist für die '''Kommunikation zwischen Threads''' zuständig. Er kann dazu '''Runnable und Message Objekte Verschicken''' und Verarbeiten.
 +
* Stellt zusätzlich eine '''Warteschlange''' für Runnables und Message Objekten zur Verfügung um diese nacheinander abzuarbeiten.
 +
==== So funktioniert es ====
 +
<pre>
 +
                                übergibt Handler Instanz                             
 +
UI-Thread -------------------------------------> Hintergrund-Thread
  
 +
                                    legt ab Runnables / Messages
 +
Hintergrund-Thread -----------------------------> Handler-Instanz
  
 +
</pre>
  
 +
=== Handler Callback mit Runnables ===
 +
* Erzeuge Handler-Instanz in UI-Thread
 +
* Erzeuge Runnable in UI-Thread
 +
* Erzeuge Hintergrund-Thread und Übergebe Verweis auf Handler
 +
* Übergebe Runnable in der run() Funktion z.B. mittels post(runnable)
 +
* Starte Hintergrund Thread
 +
* Alternativen zu post sind
 +
post(Runnable r)
 +
postAtTime(Runnable r, long uptimeMillis)
 +
postDelayed(Runnable r, long delayMillis)
  
 +
==== Beispiel ====
  
 +
=== Handler Callback mit Message ===
 +
Todo
  
 
== Old Stuff ==
 
== Old Stuff ==
...
 
 
===Threads über das Interface Runnable===
 
===Threads über das Interface Runnable===
 
'''Der Thread'''
 
'''Der Thread'''

Version vom 9. März 2013, 17:30 Uhr

Links

Einführung

UI-Thread und Hintergrund Threads

  • Jede App läuft in einem eigenen Prozess mit eigener Dalvik Virtual Machine. Für die Sichtbaren Bestandteile der App ist ein User-Interface-Thread zuständig. Die Start-Activity läuft in diesem UI-Thread.
  • Aufwändige Berechnungen frieren deshalb das UI ein. Wenn der Thread zu lange "weg" und nicht auf Benutzereingaben reagieren kann, wird er von Android gekillt (Application Not Responding - ANR.
  • Threads sind problemlos möglich aber Zugriff auf Views nur über den UI-Thread Möglich.

-> Kommunikation zwischen Hintergrund-Thread und UI-Thread notwendig.

Typisches Beispiel

  • Button Click führt zu langer Berechnung
  • Berechnung im Hintergrund-Thread
  • Anzeige des Ergebnisses in TextView

-> Problem Anzeige geht nur über UI-Thread, Berechnung geht nur über Hintergrund Thread, UI soll nach Berechnung sofort Ergebnis anzeigen.

Man braucht also etwas was es ermöglicht Threads vom Haupthread zu starten und das Ergebnis zurück zu schicken.

Lösung Callback für Threads

Runnable

Objekte die etwas ausführen können

Message

Container für Daten (z.B. Bundle)

Handler

  • Ist für die Kommunikation zwischen Threads zuständig. Er kann dazu Runnable und Message Objekte Verschicken und Verarbeiten.
  • Stellt zusätzlich eine Warteschlange für Runnables und Message Objekten zur Verfügung um diese nacheinander abzuarbeiten.

So funktioniert es

                                 übergibt Handler Instanz                              
UI-Thread -------------------------------------> Hintergrund-Thread 

                                    legt ab Runnables / Messages
Hintergrund-Thread -----------------------------> Handler-Instanz

Handler Callback mit Runnables

  • Erzeuge Handler-Instanz in UI-Thread
  • Erzeuge Runnable in UI-Thread
  • Erzeuge Hintergrund-Thread und Übergebe Verweis auf Handler
  • Übergebe Runnable in der run() Funktion z.B. mittels post(runnable)
  • Starte Hintergrund Thread
  • Alternativen zu post sind
post(Runnable r)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)

Beispiel

Handler Callback mit Message

Todo

Old Stuff

Threads über das Interface Runnable

Der Thread

Damit ein Thread weiß was er tun soll braucht er Befehlsfolgen. Diese bekommt er mit einem Runnable Objekt.

Der Thread bekommt dazu eine Referenz auf ein Runnable Objekt. So weiß er für welches runnable er zuständig ist. Dann Ruft man die Methode start() auf. Der Thread holt sich dann das Runnable und started dort die Methode run() in einer eigenen Ablaufumgebung - dem Thread.

Das Runnable

Das Runnable enthält eine Methode run() die ausgeführt wird, wenn es durch den Eltern Thread gestartet wird.

Beispiel aus dem Galileo Link s.o.


public class DateCommand implements Runnable
{
  @Override public void run()
  {
    for ( int i = 0; i < 20; i++ )
      System.out.println( new java.util.Date() );
  }
}

class CounterCommand implements Runnable
{
  @Override public void run()
  {
    for ( int i = 0; i < 20; i++ )
      System.out.println( i );
  }
}

Thread t1 = new Thread( new DateCommand() );
t1.start();

Thread t2 = new Thread( new CounterCommand() );
t2.start();

Bei der Ausgabe erkennt man das die beiden Threads gleichzeitig laufen.

Läuft der Thread schon, so löst ein zweiter Aufruf der start()-Methode eine IllegalThreadStateException aus.

Threads in Android Activities

http://android-developers.blogspot.de/2009/05/painless-threading.html

In Android läuft jede Activity in einem eigenen Thread (Main Thread). D.h. wenn diese Beschäftigt ist z.B. für eine Berechnung, dann ist auch das User Interface blockiert.

Android erlaubt ganz normale Java Threads und auf den ersten Blick funktioniert es auch.

Thread thread = new Thread(new Runnable(){
		@Override
		public void run() {
			// mach was	
		}
}); 
thread.start();

So sollte man es aber nicht machen.

Beispiel

Bild über das Netzwerk runterladen und als ImageView zeigen.

So nicht

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      Bitmap b = loadImageFromNetwork();
      mImageView.setImageBitmap(b);
    }
  }).start();
}

Um immer mit dem Hauptthread verbunden zu bleiben gibt es mehrerer Wege:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)
  • Handler

Beispiel

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

Der Nachteil ist bei allen, daß der Code schnell Komplex und unübersichtlich wird. Daher gibt es das Konzept AsyncTask

Beispiel mit AsyncTask

public void onClick(View v) {
  new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask {
     protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
     }

     protected void onPostExecute(Bitmap result) {
         mImageView.setImageBitmap(result);
     }
 }

Handlers

Handler braucht man wenn:

  • Ein Thread mit dem UserInterface kommunizieren will.
  • Ein Thread MessageQueuing, scheduling and wiederholende Tasks ausführen soll.


Der Handler wird in der Acivity (z.B. in der onCreate() Methode) erzeugt und kann runnables entgegen nehmen (oder messages von einem scheduler) , die somit zugriff auf die Activity haben ohne den Main Thread zu blockieren.

AsyncTasks

Async Task sind eine gute Wahl, wenn es darum geht längere Background Prozesse auszuführen (z.B. Downloads). Siehe Beispiel oben.