I have a custom view that overrides onMeasure.
I see onMeasure()
getting called twice, the first time with the heightMeasureSpec at 0x7fffffff - that doesn't seem to be a valid MeasureSpec value.
Then, it gets called again, that time with the proper value.
Here are the basic components, stripped down to the relevant parts:
The custom view:
public class CustomView extends ViewGroup implements SurfaceHolder.Callback {
public CustomView(Context context, AttributeSet as) {
super(context, as);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_view, this, true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
}
}
The layout (again, stripped down to keep this as brief as possible):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
And here is the layout that contains it:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<CustomView
android:id="@+id/custom_view"
android:layout_width="@dimen/custom_size"
android:layout_height="@dimen/custom_size"
/>
</RelativeLayout>
</ScrollView>
</LinearLayout>
Key observations here:
- The custom view has a fixed width and height (the custom size is 128dp).
- The view itself is inside a RelativeLayout.
- All of this is inside a ScrollView.
In this scenario, I get onMeasure called first with 0x40000100, 0x7fffffff, and then again with 0x40000100, 0x40000100, which is what I would have expected in the first place.
Maybe it's perfectly normal for onMeasure to be called with an invalid height first? I could ignore it, but I don't want to add any hacks here.
ANSWER: It's a bug in the operating system that has been fixed, documented here:
In platform version 17 and lower, RelativeLayout was affected by a measurement bug that could cause child views to be measured with incorrect MeasureSpec values. (See MeasureSpec.makeMeasureSpec for more details.) This was triggered when a RelativeLayout container was placed in a scrolling container, such as a ScrollView or HorizontalScrollView. If a custom view not equipped to properly measure with the MeasureSpec mode UNSPECIFIED was placed in a RelativeLayout, this would silently work anyway as RelativeLayout would pass a very large AT_MOST MeasureSpec instead.
I'm not going to post this as an answer, Snicolas has been nice enough to look at this so he deserves his accepted answer.