【问题标题】:How Handler affects the way onReceiveResult (ResultReceiver) is invoked?Handler 如何影响 onReceiveResult (ResultReceiver) 的调用方式?
【发布时间】:2016-03-21 03:41:30
【问题描述】:

看,我有以下代码:

我的行动:

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
            }
        })

我的服务:

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

我的应用程序在“imageView.setBackgroundDrawable(bitmap)”行失败,但出现以下异常:

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有什么影响?

【问题讨论】:

    标签: android handler


    【解决方案1】:

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

    【讨论】:

    • 我有一个疑问。 ResultReceiver.onReceiveResult 会一直在非 UI 线程上运行吗?
    • 不,这是使用 Handler 保证它将在正确的线程上运行。通常不保证接收者将在哪个线程上调用。
    • 知道了!它基于调用结果接收器的线程。感谢您的快速回复。
    • 这个答案为我节省了数小时的调试时间。谢谢!
    • 如果可能,您能否在源代码中提供开始探索的起点?最好从 ResultReceiver 开始并继续工作还是...?
    【解决方案2】:

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

    很难准确解释您提供的 sn-ps 需要更改哪些内容。

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

    一些有用的链接:

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

    What is the Android UiThread (UI thread)

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

    【讨论】:

    • 是的,我看到这个问题是因为 UI 更新是从另一个线程执行的。但是当我传递一个默认处理程序时,这不会发生。因此,当我通过它时,它是否可以从 UI 线程中处理所有内容而不是创建新线程?感谢您的链接,看起来很有趣!
    【解决方案3】:

    以下内容对我有用。您可以使用“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));
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多