2009-07-21 13 views
29

Ich habe eine Aktivität namens A, und auf die Auswahl von Menüelement 0, spawn Service B, der eine ausführbare C in einem neuen Thread startet. Ich habe eine Textview in Aktivität A, die ich in dem Thread C zugreifen möchteSo greifen Sie auf die ursprüngliche Aktivität der Ansichten von launched Hintergrund-Service

Ich habe versucht, das Textview ein öffentliches statisches Feld zu machen, aber das erzeugt die folgenden Fehler:

07-21 07:26:25.723: ERROR/AndroidRuntime(1975): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.view.ViewRoot.checkThread(ViewRoot.java:2440) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.view.ViewRoot.invalidateChild(ViewRoot.java:522) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:540) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.view.ViewGroup.invalidateChild(ViewGroup.java:2332) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.view.View.invalidate(View.java:4437) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.widget.TextView.updateAfterEdit(TextView.java:4593) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.widget.TextView.handleTextChanged(TextView.java:5932) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:6081) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.sendTextChange(SpannableStringBuilder.java:889) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:352) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:269) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:432) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:259) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:28) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.widget.TextView.append(TextView.java:2191) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at android.widget.TextView.append(TextView.java:2178) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at com.android.peekaboo.DoScan$scanBody.run(DoScan.java:36) 
07-21 07:26:25.723: ERROR/AndroidRuntime(1975):  at java.lang.Thread.run(Thread.java:1058) 

Ich habe auch dachte über den Versuch, den View durch eine Absicht zu übergeben, weiß aber nicht, wie das funktionieren würde. Was muss ich tun, damit dies funktioniert?

Antwort

21

Sie müssen Widgets aus dem GUI-Thread aktualisieren, auch bekannt als "der Thread, der die Ansichtshierarchie erstellt hat". Der Standardweg hierfür ist über Handler s und ein Beispiel für die Verwendung von Handlern finden Sie in der (erweitern Sie 'Beispiel ProgressDialog mit einem zweiten Thread').

1

Die andere Möglichkeit besteht darin, os.android.AsyncTask für die Verarbeitung zu verwenden.

2

Sie möchten Widgets aus einem Dienst nicht direkt manipulieren.

Nehmen Sie zum Beispiel an, der Benutzer gleitet die Tastatur ihres G1 aus. Ihre Aktivität wird zerstört und neu erstellt. Ihr Dienst hält jedoch Widgets von einer nicht mehr existierenden Aktivität fest. Im besten Fall werden die Updates nicht auftreten. Im schlimmsten Fall führen die Aktualisierungen zu einem Absturz, oder die Anwendung verliert Speicher, da die alte Aktivität nicht in den Garbage-Collected-Modus versetzt werden kann, da Ihr Dienst weiterhin vorhanden ist.

Das Benachrichtigen von Aktivitäten über Dienste ist in Ordnung, solange Sie eine angemessene Isolation zwischen ihnen haben und die Aktivität sich selbst vom Dienst trennt, wenn sie zerstört wird.

25

Ich hatte ein ähnliches Problem, wo ein ListView auf die Web-Service-Antwort von einem separaten Thread aktualisiert werden musste.

Nach der Analyse eines similar question & example, hier ist eine Lösung, die für Sie arbeiten sollten:

public class A extends Activity implements Callback { 

    callserviceB() { } // where your service B being called; 

    @Override 
    public void returnServiceResponse() { 
      workOnResponse(); 
      handler.sendEmptyMessage(0); 
    } 

    private Handler handler = new Handler() { 
      public void handleMessage(Message msg) { 
       //update your view from here only. 
      } 
    } 
} 

public class B implements Runnable { 
    Callback callback; 

    public void run() { 
     //your business logic. 
     callback.returnServiceResponse(); 
    } 
} 

public interface Callback { 
    public void returnServiceResponse(); 
} 
+2

Code-Beispiele sind immer so viel nützlicher als Beschreibungen. Danke :) – HXCaine

+0

Danke, dieses Problem habe mich schon lange verfolgt! Vielen Dank! – Daniel