I asked this question on 
SO<http://stackoverflow.com/questions/7015097/best-practices-for-dealing-with-expensive-view-height-calculation>a
 month ago but got no answer. Maybe I'll have better luck here. :)

I keep running into a sizing and layout problem for custom views and I'm 
wondering if anyone can suggest a "best practices" approach. The problem is 
as follows. Imagine a custom view where the height required for the content 
depends on the width of the view (similar to a multi-line TextView). 
(Obviously, this only applies if the height isn't fixed by the layout 
parameters.) The catch is that for a given width, it's rather expensive to 
compute the content height in these custom views. In particular, it's too 
expensive to be computed on the UI thread, so at some point a worker thread 
needs to be fired up to compute the layout and when it is finished, the UI 
needs to be updated.

The question is, how should this be designed? I've thought of several 
strategies. They all assume that whenever the height is calculated, the 
corresponding width is recorded.

The first strategy is shown in this code:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   int width = measureWidth(widthMeasureSpec);
   setMeasuredDimension(width, measureHeight(heightMeasureSpec, width));
}

private int measureWidth(int widthMeasureSpec) {
   // irrelevant to this problem
}

private int measureHeight(int heightMeasureSpec, int width) {
   int result;
   int specMode = MeasureSpec.getMode(measureSpec);
   int specSize = MeasureSpec.getSize(measureSpec);
   if (specMode == MeasureSpec.EXACTLY) {
       result = specSize;
   } else {
       if (width != mLastWidth) {
           interruptAnyExistingLayoutThread();
           mLastWidth = width;
           mLayoutHeight = DEFAULT_HEIGHT;
           startNewLayoutThread();
       }
       result = mLayoutHeight;
       if (specMode == MeasureSpec.AT_MOST && result > specSize) {
           result = specSize;
       }
   }
   return result;
}

When the layout thread finishes, it posts a Runnable to the UI thread to set 
mLayoutHeight to the calculated height and then call requestLayout() (and 
invalidate()).

A second strategy is to have onMeasure always use the then-current value for 
mLayoutHeight (without firing up a layout thread). Testing for changes in 
width and firing up a layout thread would be done by overriding 
onSizeChanged.

A third strategy is to be lazy and wait to fire up the layout thread (if 
necessary) in onDraw.

I would like to minimize the number of times a layout thread is launched 
and/or killed, while also calculating the required height as soon as 
possible. It would probably be good to minimize the number of calls to 
requestLayout() as well.

>From the docs, it's clear that onMeasure might be called several times 
during the course of a single layout. It's less clear (but seems likely) 
that onSizeChanged might also be called several times. So I'm thinking that 
putting the logic in onDraw might be the better strategy. But that seems 
contrary to the spirit of custom view sizing, so I have an admittedly 
irrational bias against it.

Other people must have faced this same problem. Are there approaches I've 
missed? Is there a best approach?

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to