Handler如何影响onReceiveResult(ResultReceiver)的调用方式?

看,我有以下代码:

我的行动:

final Intent intent = new Intent(getApplicationContext(), MyService.class) .putExtra(UploadService.EXTRA_RESULT_RECEIVER, new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); String result = resultData.getString(MyService.EXTRA_RESULT_SUCCESS); ... imageView.setBackgroundDrawable(bitmap);// here my code fails } }) 

为MyService:

  Bundle b = new Bundle(); b.putString(EXTRA_RESULT_SUCCESS, response.toString()); resultReceiver.send(0, b); 

我的应用程序在“imageView.setBackgroundDrawable(bitmap)”行上失败,但有以下exception:

 11-13 16:25:38.986: ERROR/AndroidRuntime(3586): FATAL EXCEPTION: IntentService[MyService] android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 

但是当我像这样定义接收器(带处理程序)时,这不会发生:

 new ResultReceiver(new Handler()){.../*here goes the same code as in the first example. nothing has been changed*/} 

所以。 当我传递默认处理程序时它不会失败。 我问为什么 ? 在这两种方式中我的代码都被调用,但是当没有Handler指定时它会失败。 Handler有什么影响?

Handler绑定到Android框架并确保在Handler的回调中运行的任何代码都在父Activity的主Looper线程上执行,该线程是进行所有Activity生命周期回调和UI调用的地方。 如果你真的想了解它是如何工作的,你可以浏览Github上的源代码,但是在Handler中运行代码几乎可以保证把东西放在正确的位置。

问题是因为从服务的线程调用imageView.setBackgroundDrawable()。 这是不正确的。 您需要确保从UI线程执行任何UI更新。

很难从您提供的片段中准确解释需要改变的内容。

Android提供了许多技术,允许非UI线程与UI组件(以及Handler类之一)进行交互。 恕我直言,如果您想开发优秀的Android应用程序,这是最合适的概念之一。

一些有用的链接:

http://developer.android.com/resources/articles/painless-threading.html

什么是Android UiThread(UI线程)

http://www.vogella.de/articles/AndroidPerformance/article.html

以下适用于我。 您可以使用“runOnUiThread”方法在UI活动的同一个线程中运行位图更新。 您应该将以下类定义为UI活动的内部类:

 class UpdateUI implements Runnable { Bitmap newBitmap; public UpdateUI(Bitmap newBitmap) { this.newBitmap = newBitmap; } public void run() { imageView.setBackgroundDrawable(newBitmap); } } 

然后在你的resultReceiver中:

 @Override protected void onReceiveResult(int resultCode, Bundle resultData) { // after get your bitmap runOnUiThread(new UpdateUI(receivedBitmap)); ... }