29

我有一个名为 A 的活动,在选择菜单项 0 时,它会生成服务 B,该服务在新线程中启动一个可运行的 C。我在活动 A 中有一个 TextView,我想在线程 C 中访问它。

我尝试将 TextView 设为公共静态字段,但这会产生以下错误:

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)

我也考虑过尝试通过意图传递视图,但不知道这将如何工作。我需要什么才能完成这项工作?

4

4 回答 4

25

我遇到了类似的问题,需要在来自单独线程的 Web 服务响应上更新 ListView。

在分析了类似的问题示例之后,这里有一个适合您的解决方案:

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();
}
于 2010-09-03T05:00:35.987 回答
21

您必须从 GUI 线程更新小部件,也就是“创建视图层次结构的线程”。执行此操作的标准方法是通过Handlers,可以在ProgressDialog 示例中找到如何使用处理程序的示例(展开“带有第二个线程的示例 ProgressDialog”)。

于 2009-07-21T09:56:46.457 回答
2

您真的不想直接从服务中操作小部件。

例如,假设用户滑出她的 G1 的键盘。您的活动被销毁并重新创建。但是,您的服务正在使用现已失效的活动中的小部件。充其量不会发生更新。在最坏的情况下,更新将导致崩溃,或者您的应用程序将泄漏内存,因为旧的活动无法被垃圾收集,因为您的服务仍然保留它。

让服务通知活动是可以的,只要你在它们之间有适当的隔离,并且活动在被销毁时会从服务中分离出来。

于 2009-07-21T21:39:34.780 回答
1

另一种方法是利用os.android.AsyncTask进行处理。

于 2009-07-21T13:04:25.433 回答