OnMeasure is called 1500+ times
I recently noticed a significant performance issue in my application. I essentially have the following layout ...
DESCRIPTION
In short, there is ViewPager
one that contains 3 RelativeLayout
as pages. Each page contains a number TextView
s. I recently noticed a lot of lag when I typed in EditText
that has TextWatcher
to execute a quick SQL query for autocomplete. My HTC One M8 stutters and lags when I was typing, but I know this is not a slow request because I was measuring requests taking only about 7ms.
I used profiling, Systrace and regular old Log
debugging and found that every time I typed a character, EditText
about 1700 calls onMeasure
were made to TextView
inside RelativeLayout
A, B, and C. In total, there are only about 15 independent pages on the pages TextView
. I noticed that each onMeasure
is called hundreds of times, not once or twice as usual.
Question
I don't know why typing text EditText
on page B will cause others TextView
on pages A and C to be "re-measured" as well. More importantly, does anyone know why onMeasure
it gets called so often? And does anyone know of a solution to significantly reduce the number of calls by onMeasure
?
DETAILS
This might help: I was actually able to reduce the number of calls onMeasure
to around 900 by removing RelativeLayout
2, which might suggest that call propagation onMeasure
starts outside ViewPager
.
source to share
Although I don't have enough information to identify a specific problem, I can tell you in general what is happening:
Calling the root view measure
causes each sub-view to be called measure
, etc. down the tree.
Suppose a view called "current view", after each of its submatrices measures itself, decides that there is not enough room for all the children. He will ask each of them to measure themselves again, suggesting the maximum size. Suppose a view called "Relative Layout B" radically changes its size based on the specified max. Because the change is so large, the "current view" has to query each child again. This loop can easily take a couple more iterations.
When the "current view" decides on its size, it returns to the "View Pager". Suppose the "View Pager" doesn't have three viewing spaces and needs to ask them to re-measure from max. We now have at least 20 calls to TextView onMeasure
. If each of the other views above the ViewPager is repeated multiple times, pretty soon you start seeing big numbers.
The best solution, as you already pointed out, is to decrease the depth of this tree. Alternatively, you can use layout managers which have much simpler measurement algorithms (FrameLayout, LinearLayout)
Nevertheless,1500. One of these looks does something strange. You should be able to identify it very easily using the TreeView tool in the DDMS package. In eclipse, this is called a TreeView. In Studio, click the Android icon and switch to the hierarchy view perspective. You can also run it from the command line from the SDK tools directory.
Added: If you connect the Hierarchy Viewer to your application while it is running, you will see the entire view tree in one of your panels. Each node in the tree will have three colored gumdrops towards the bottom. The first gumdrop represents the measurement phase. If the gumdrop is green, the measurement phase for that view is fast. If it's yellow, then the node is in the top 50 percentile of nodes in the layout. If it is red, it is the slowest in the layout.
You should be able to follow the yellow before the offending gaze.
source to share