Android 如何从衍生的后台服务访问原始活动的视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1157814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to access original activity's views from spawned background service
提问by montooner
I have an activity called A, and on the selection of menu item 0, it spawns service B, which starts a runnable C in a new thread. I have a TextView in activity A, which I want to access in thread C.
我有一个名为 A 的活动,在选择菜单项 0 时,它会生成服务 B,它在新线程中启动一个可运行的 C。我在活动 A 中有一个 TextView,我想在线程 C 中访问它。
I've tried making the TextView a public static field, but that generates the following error:
我尝试将 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)
I have also considered trying to pass the View through an intent, but do not know how that would work. What do I need to make this work?
我也考虑过尝试通过意图传递视图,但不知道这将如何工作。我需要什么才能完成这项工作?
采纳答案by Josef Pfleger
You have to update widgets from the GUI thread, aka 'the thread that created the view hierarchy'. The standard way to do this is via Handler
s and an example of how to use handlers can be found in the ProgressDialog Example(expand 'Example ProgressDialog with a second thread').
您必须从 GUI 线程(即“创建视图层次结构的线程”)更新小部件。执行此操作的标准方法是通过Handler
s 并且可以在ProgressDialog 示例中找到如何使用处理程序的示例(展开“带有第二个线程的示例 ProgressDialog”)。
回答by Sagar
I was having a similar issue where a ListView was required to be updated on the web-service response coming from a separate thread.
我遇到了类似的问题,需要在来自单独线程的 Web 服务响应上更新 ListView。
After analyzing a similar question& example, here is a solution which should work for you:
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();
}
回答by CommonsWare
You really do not want to be directly manipulating widgets from a service.
您真的不想直接操作来自服务的小部件。
For example, suppose the user slides out the keyboard of her G1. Your activity is destroyed and recreated. Your service, however, is holding onto widgets from a now-defunct activity. At best, the updates will not occur. At worst, the updates will cause a crash, or your application will leak memory because the old activity cannot be garbage-collected, because your service still holds onto it.
例如,假设用户将 G1 的键盘滑出。您的活动被销毁并重新创建。但是,您的服务正在保留一个现已不复存在的活动的小部件。充其量,不会发生更新。在最坏的情况下,更新将导致崩溃,或者您的应用程序将泄漏内存,因为旧活动无法被垃圾收集,因为您的服务仍然保留它。
Having services notify activities is OK, so long as you have decent isolation between them and the activity detaches itself from the service when it is destroyed.
让服务通知活动是可以的,只要您在它们之间有良好的隔离并且活动在销毁时与服务分离。
回答by yanchenko
The other way is to utilize os.android.AsyncTaskfor processing.
另一种方法是利用os.android.AsyncTask进行处理。