Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Handler affects the way onReceiveResult (ResultReceiver) is invoked?

Look, I have the following code:

My Action:

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

And my application fails on line "imageView.setBackgroundDrawable(bitmap)" with the following 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.

But this doesn't happen when I define receiver like this (with handler):

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

So. It doesn't fail when I pass a default Handler. And I ask Why? In both ways my code is invoked, but when no Handler specified it fails. What influence does Handler have?

like image 518
andrii Avatar asked Nov 13 '11 14:11

andrii


2 Answers

The Handler ties into the Android framework and ensures that any code that is run in the Handler's callbacks is executed on the parent Activity's main Looper thread which is where all the Activity lifecycle callbacks and UI calls are made. If you really want to understand how it works you can wander through the source on Github, but running code in a Handler is pretty much guaranteed to put things in the right place.

like image 104
Femi Avatar answered Oct 07 '22 08:10

Femi


The problem is because imageView.setBackgroundDrawable() is called from your service's thread. This is incorrect. You need to make sure that any UI update is executed from the UI thread.

It is hard to explain exactly what needs to change from the snippets you provide.

Android provides a number of techniques to allow non-UI threads to interact with UI components (and the Handler class one of the option). IMHO, this is one of the most critical concept to get right if you want to develop good Android applications.

Some useful links:

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

What is the Android UiThread (UI thread)

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

like image 39
kctang Avatar answered Oct 07 '22 08:10

kctang