web-dev-qa-db-ja.com

生成されたバックグラウンドサービスから元のアクティビティのビューにアクセスする方法

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)

ビューをインテントに通すことも検討しましたが、それがどのように機能するかわかりません。これを機能させるには何が必要ですか?

29
montooner

GUIスレッド(別名「ビュー階層を作成したスレッド」)からウィジェットを更新する必要があります。これを行う標準的な方法は Handler sで、ハンドラーの使用例は ProgressDialog Example (expand 'Example ProgressDialog with 2番目のスレッド ')。

21
Josef Pfleger

別のスレッドからの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();
}
25
Sagar

サービスからウィジェットを直接操作したくない場合。

たとえば、ユーザーが彼女のG1のキーボードを引き出したとします。アクティビティが破棄され、再作成されます。ただし、あなたのサービスは、今はなくなった活動からのウィジェットを保持しています。せいぜい、更新は行われません。最悪の場合、更新によりクラッシュが発生するか、サービスが保持しているために古いアクティビティをガベージコレクションできないため、アプリケーションがメモリリークを起こします。

サービスがアクティビティに通知するようにしても、アクティビティが適切に分離されていて、アクティビティが破棄されるとアクティビティからサービスから切り離されます。

2
CommonsWare

もう1つの方法は、処理にos.Android.AsyncTaskを利用することです。

1
yanchenko