Как получить доступ к исходным представлениям активности из порожденного фонового сервиса - PullRequest
29 голосов
/ 21 июля 2009

У меня есть действие с именем A, и при выборе пункта меню 0 он порождает службу B, которая запускает работоспособный C в новом потоке. У меня есть TextView в действии A, к которому я хочу получить доступ в потоке 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 ]

25 голосов
/ 03 сентября 2010

У меня была похожая проблема, когда 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();
}
21 голосов
/ 21 июля 2009

Вы должны обновить виджеты из потока GUI, то есть «потока, который создал иерархию представлений». Стандартный способ сделать это через Handler с, а пример использования обработчиков можно найти в ProgressDialog Example (разверните «Пример ProgressDialog со вторым потоком») .

2 голосов
/ 22 июля 2009

Вы действительно не хотите напрямую манипулировать виджетами из службы.

Например, предположим, что пользователь выдвигает клавиатуру из своего G1. Ваша деятельность разрушена и воссоздана. Ваш сервис, однако, удерживает виджеты из ныне несуществующей деятельности. В лучшем случае обновления не произойдут. В худшем случае, обновления вызовут сбой, или ваше приложение утечет память, потому что старая активность не может быть собрана сборщиком мусора, потому что ваша служба все еще удерживает ее.

Работать с уведомлениями о службах - это нормально, если у вас есть приличная изоляция между ними и действие отсоединяется от службы, когда она уничтожается.

1 голос
/ 21 июля 2009

Другой способ - использовать os.android.AsyncTask для обработки.

...