Wo kann ich Threads in der Android Service-class stoppen / zerstören?

Ich habe einen Thread-Dienst wie folgt erstellt:

public class TCPClientService extends Service{ ... @Override public void onCreate() { ... Measurements = new LinkedList(); enableDataSending(); } @Override public IBinder onBind(Intent intent) { //TODO: Replace with service binding implementation return null; } @Override public void onLowMemory() { Measurements.clear(); super.onLowMemory(); } @Override public void onDestroy() { Measurements.clear(); super.onDestroy(); try { SendDataThread.stop(); } catch(Exception e){ ... } } private Runnable backgrounSendData = new Runnable() { public void run() { doSendData(); } }; private void enableDataSending() { SendDataThread = new Thread(null, backgrounSendData, "send_data"); SendDataThread.start(); } private void addMeasurementToQueue() { if(Measurements.size() <= 100) { String measurement = packData(); Measurements.add(measurement); } } private void doSendData() { while(true) { try { if(Measurements.isEmpty()) { Thread.sleep(1000); continue; } //Log.d("TCP", "C: Connecting..."); Socket socket = new Socket(); socket.setTcpNoDelay(true); socket.connect(new InetSocketAddress(serverAddress, portNumber), 3000); //socket.connect(new InetSocketAddress(serverAddress, portNumber)); if(!socket.isConnected()) { throw new Exception("Server Unavailable!"); } try { //Log.d("TCP", "C: Sending: '" + message + "'"); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true); String message = Measurements.remove(); out.println(message); Thread.sleep(200); Log.d("TCP", "C: Sent."); Log.d("TCP", "C: Done."); connectionAvailable = true; } catch(Exception e) { Log.e("TCP", "S: Error", e); connectionAvailable = false; } finally { socket.close(); announceNetworkAvailability(connectionAvailable); } } catch (Exception e) { Log.e("TCP", "C: Error", e); connectionAvailable = false; announceNetworkAvailability(connectionAvailable); } } } ... } 

Nachdem ich die Anwendung geschlossen habe, funktioniert das Telefon sehr langsam und ich schätze, es ist wegen Thread-Terminierungserrors.

Weiß jemand, was der beste Weg ist, alle Threads vor dem Beenden der Anwendung zu beenden?

Nachtrag : Das Android-Framework bietet viele Helfer für einmalige Arbeit, Hintergrundarbeit usw., die in vielen Fällen dem Versuch, einen eigenen Thread zu erstellen, vorzuziehen sein könnte. Wie in einem der folgenden Posts erwähnt, ist AsyncTask ein guter Ausgangspunkt. Ich ermutige die Leser, erst einmal in die Rahmenbestimmungen zu schauen, bevor sie überhaupt darüber nachdenken, ihr eigenes Threading zu machen.

Es gibt mehrere Probleme in der von Ihnen geposteten Codebeispiel, die ich der Reihe nach angehen werde:

1) Thread.stop () ist seit geraumer Zeit veraltet, da abhängige Variablen unter Umständen in inkonsistenten Zuständen verbleiben können. Weitere Informationen finden Sie auf dieser Sun-Antwortseite (Bearbeiten: Dieser Link ist jetzt inaktiv . Auf dieser Seite finden Sie Informationen dazu, warum Sie Thread.stop () nicht verwenden sollten ). Eine bevorzugte Methode zum Anhalten und Starten eines Threads ist wie folgt (vorausgesetzt, der Thread wird etwas unbestimmt ausgeführt):

 private volatile Thread runner; public synchronized void startThread(){ if(runner == null){ runner = new Thread(this); runner.start(); } } public synchronized void stopThread(){ if(runner != null){ Thread moribund = runner; runner = null; moribund.interrupt(); } } public void run(){ while(Thread.currentThread() == runner){ //do stuff which can be interrupted if necessary } } 

Dies ist nur ein Beispiel dafür, wie man einen Thread stoppt, aber das Mitnehmen ist, dass Sie dafür verantwortlich sind, einen Thread wie jede andere Methode zu beenden. Pflegen Sie eine Methode der Cross-Thread-Kommunikation (in diesem Fall eine flüchtige Variable, könnte auch durch einen Mutex usw. sein) und verwenden Sie in Ihrer Thread-Logik diese Kommunikationsmethode, um zu prüfen, ob Sie den Vorgang vorzeitig beenden, bereinigen usw.

2) Ihre Messungsliste wird von mehreren Threads (dem Ereignis-Thread und Ihrem Benutzer-Thread) gleichzeitig ohne Synchronisierung aufgerufen. Es sieht so aus, als müssten Sie Ihre eigene Synchronisation nicht rollen, Sie können eine BlockingQueue verwenden .

3) Sie erstellen einen neuen Socket für jede Iteration Ihres sendenden Threads. Dies ist eine ziemlich schwergewichtige Operation und nur dann wirklich sinnvoll, wenn Sie erwarten, dass Messungen extrem selten sind (sagen wir eine Stunde oder weniger). Entweder möchten Sie einen dauerhaften Socket, der nicht in jeder Schleife des Threads neu erstellt wird, oder Sie möchten einen One-Shot-Runnable, den Sie “feuern und vergessen” können, der einen Socket erstellt, alle relevanten Daten sendet und beendet. (Ein kurzer Hinweis zur Verwendung eines persistenten Sockets, Socket-Methoden, die blockieren, wie das Lesen, kann nicht durch Thread.interrupt () unterbrochen werden, und wenn Sie also den Thread stoppen möchten, müssen Sie sowohl den Socket als auch den Interrupt schließen)

4) Es hat wenig Sinn, eigene Exceptions innerhalb eines Threads zu casting, es sei denn, man erwartet, sie irgendwo anders zu fangen. Eine bessere Lösung besteht darin, den Fehler zu protokollieren und den Thread zu stoppen, wenn er nicht behebbar ist. Ein Thread kann sich selbst mit Code wie (im selben Kontext wie oben) stoppen:

 public void run(){ while(Thread.currentThread() == runner){ //do stuff which can be interrupted if necessary if(/*fatal error*/){ stopThread(); return; //optional in this case since the loop will exit anyways } } } 

Wenn Sie sichergehen wollen, dass ein Thread mit dem Rest Ihrer Anwendung endet, ist es eine gute Methode, Thread.setDaemon (true) nach der Erstellung und vor dem Start des Threads aufzurufen. Dadurch wird der Thread als Daemon-Thread gekennzeichnet, dh die VM stellt sicher, dass sie automatisch zerstört wird, wenn keine nicht-Daemon-Threads ausgeführt werden (z. B. wenn Ihre App beendet wird).

Die Einhaltung der Best Practices in Bezug auf Threads sollte sicherstellen, dass Ihre App das Telefon nicht hängt oder verlangsamt, obwohl sie ziemlich komplex sein kann 🙂

Tatsächlich brauchen Sie die Variable “runner” nicht wie oben beschrieben, etwas wie:

 while (!interrupted()) { try { Thread.sleep(1000); } catch (InterruptedException ex) { break; } } 

Aber im Allgemeinen ist das Sitzen in einer Thread.sleep () – Schleife eine wirklich schlechte Idee.

Sehen Sie sich die AsyncTask-API in der neuen 1.5-API an. Es wird wahrscheinlich Ihr Problem eleganter lösen als die Verwendung eines Dienstes. Ihr Telefon wird langsam, weil der Dienst nie herunterfährt – es gibt nichts, was dazu führt, dass der Dienst sich selbst umbringt.