4

I know that the UI elements (View hierarchy) may only be manipulated from the UI thread. For a background operation, the AsyncTask can be used, which offers event handlers to reach the UI thread.

To be brief, is it allowed to instantiate a View (tied to getApplicationContext()) in a non-UI thread? This custom View descendant -- once instantiated -- is added to the view hierarchy from the UI thread. So only the constructor call is done inside an Asynctask.doInBackground(); it's attaching (addView(...)) to the Activity's root layout hierarchy is still done in the UI thread.

In details:

public MyView extends View { public MyView(Context context) { ... } ... } 
  1. I made a custom View, with overriden onDraw(...) etc.

  2. When the user clicks a certain MenuItem in my main Activity, another Activity (MyOtherActivity) is created and displayed which screen is exactly MyView

  3. Since the screen of MyOtherActivity must be displayed instantly, I pre-instantiate MyView in an AsyncTask while the user is somewhere else in the main Activity (i.e. he hasn't clicked that MenuItem yet). The MyView reference is stored in a static data member.

  4. When MyOtherActivity.onCreate() is called, its constructor code takes MyView from the static, and adds it to its layout root hierarchy via addView(...).

  5. (I'm aware that the static variable may introduce memory leaks, so I set it to null once it's not needed.)

Isn't it a problem (and might it introduce unexpected issues) that MyView is instantiated in a different thread (and takes the return value of getApplicationContext() in its constructor)?

4
  • 1
    Cross-referencing the android-developers discussion on this: groups.google.com/group/android-developers/browse_thread/thread/… Commented Jun 26, 2012 at 23:06
  • Thanks, Mark. For all readers: to be brief, DO NOT do what I did. Always instantiate all Views from the UI thread. I'll answer my own question after the 2 days limit ends. Now I'll just edit it. Commented Jun 26, 2012 at 23:11
  • @ThomasCalc I don't see any reason we need to wait two days for an answer. I think this is a good question, and it deserves a real answer (so I've just provided one). Commented Jun 27, 2012 at 0:52
  • @DarshanComputing When I was newly registered, there was a 2 days limit, but maybe it still applies. So it's a good idea that you added one, thanks. I've just set it to accepted. Commented Jun 27, 2012 at 0:54

2 Answers 2

5

The definitive answer appears in the documentation for View, under the heading "Event Handling and Threading":

Note: The entire view tree is single threaded. You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler.

So it's not just things that obviously affect the appearance of the UI, like addView(), but "any method on any View".

The discussion on android-developers that @CommonsWare linked to has more than one high-level engineer from the Android framework team confirming that this is to be taken seriously.

Sign up to request clarification or add additional context in comments.

5 Comments

The documentation you quote might be a bit confusing to beginners though. We know that "any method" means the constructor too, since the constructor is practically method too. The thing that may confuse begineers is that the documentation implies that the rule applies to method calls on EXISTING views only ("on any view"), and does not state anything about their CONSTRUCTION (instantiation).
I didn't mean generally confusing, of course. Just that if they ask: "hmm, can I instantiate a View here? Let's check the documentation" then he will only see method calls. And what do they teach in school? That you can call (instance) methods only after you instantiate the object. So beginners might jump into the wrong conclusion that the documentation applies to existing Views only.
@ThomasCalc It's partially because of that subtlety that I think this is such a good question. I too found myself thinking "I know you oughtn't do things to the UI outside the UI thread, but maybe you can get away with instantiating a View on another thread, as long as you add it to the UI on the UI thread." I'm glad you asked, and I'm glad to have Dianne Hackborn and Romain Guy confirming the answer. I do think "any method on any view" is clear and unambiguous, even without their confirmation. Anyway, thanks -- I now have a better mental model than "UI things happen on the UI thread".
IMO it's unambigious, but for beginners, sometimes more info might be handy (like "any method on any view, including their constructor"). Yes, "UI things happen on the UI thread" is very general, and sometimes the border is not so obvious, e.g. consider the official AsyncDrawable (which is not created async at all, just its underlying bitmap).
There is always a great explanation under discussions that is much more clear about why you "must not" do something. Wish android docs were a bit more detailed like this one "Even instantiating a view from one thread and attaching it to a view hierarchy in another is not safe, because many views will internally create Handler objects that are bound to whatever thread they were created on, causing you to have parts of your view hierarchy running on the wrong thread with bad results." simple one-line is worthy of probably whole shitty android docs that only says "must not"
0

This is an example, in how to add a view to a FrameLayout using AsyncTask

public void addFLview(View view) { MyAsyncTask as = new MyAsyncTask(); as.execute(view); } 

AsyncTask class

private class MyAsyncTask extends AsyncTask<View, Void, View> { @Override protected View doInBackground(View... params) { return params[0]; } @Override protected void onPostExecute(View view) { super.onPostExecute(view); myFrameLayout.addView(view); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.