2

The following code in an AsycnTask:

@Override
protected Boolean doInBackground(View... params) {

try{

    Drawable drawPhoto = DataDatero.ImageDownload(taskPhotoName);
    ((ImageView)params[0]).setImageDrawable(drawPhoto);
    ((TextView)params[1]).setText(taskItemListText);
    ((TextView)params[2]).setTextColor(taskColore);
    ((TextView)params[2]).setText(taskItemStockText);
    [...]
}

Throws a CalledFromWrongThreadException , describing that:

Only the original thread that created a view hierarchy can touch its views

This has been discussed in plenty of questions: example , another example ; and all reach the same conclusion.

But what I'm not only getting the Exception..

I call that execute from a getView in a List adapter, and the images (params[0]) are updated in the view while the exception is thrown for the text. Also, if I leave only the textview updates , the text is updated and no exception is thrown.

If I update the TextView first and the ImageView after, some text and images are updated while some images are not (that imageDownload includes a 2-3 sec network operation)

Why some of them are updated and others are not?

Notes: this was tested only with sdk 4.0, v4 support, on api 16 emulation. I fixed it and I'm not touching the views in doInBackground The second example is something similar... is it that the operation gets validated if onCreate is not finished?

Community
  • 1
  • 1
quinestor
  • 1,432
  • 4
  • 19
  • 40

4 Answers4

3

I have come across a similar issue and asked a question here (self answered after a good bit of digging).

Essentially what it boils down to is that, contrary to what everybody thinks, you can modify UI elements from an AsyncTask execute() if those views haven't gone through a layout traversal yet. This happens asynchronously to the main flow of execution (activity lifecycle methods/callbacks), so if the View in question is created shortly before execute() is called, you can access them (meaning, the exception isn't thrown, it's of course still really bad practice and not advisable). Because execute() happens on another thread, the layout traversals (which run on the UI thread) may finish while your execute() is running, which explains why only some views may be modified and others throw the exception. It also explains why "leaving only the textview updates" (and presumably removing the ImageView updates) results in those updates "magically" working too. Since this is a timing related issue, it depends on many factors, among other things how long Drawable drawPhoto = DataDatero.ImageDownload(taskPhotoName); takes to run.

PS: I realise this is a late answer, but I think this can be useful for somebody finding this answer first, there aren't many posts dealing with issues like this.

Community
  • 1
  • 1
ci_
  • 8,594
  • 10
  • 39
  • 63
0

The exception is clear enough. You can not update UI element from a thread different from the UI Thread. doInBackground executes code in a different thread

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
0

Why cant you pass the information to update the UI to the onPostExecute method? This is where the UI is intended to be updated.

jamis0n
  • 3,610
  • 8
  • 34
  • 50
  • i was not asking how to fix, i did that already, i just found it weird that some views are altered regardless that i do it in doInBackground. That's why I included that last note – quinestor Dec 14 '12 at 16:45
0

When you run the execute method of your task, the doInBackground method is executed in a background thread.

And you are not allowed to modify UI from a background thread.

So, don't modify the UI in the doInBackground method.

You should do this UI stuff in onPostExecute method instead, which is guaranteed to be executed in UI thread.

sdabet
  • 18,360
  • 11
  • 89
  • 158
  • i was not asking how to fix, i did that already, i just found it weird that some views are altered regardless that i do it in doInBackground. That's why I cluded that last note – quinestor Dec 14 '12 at 16:46