While looking at performance problems in my app, I discovered that each button press was triggering a call to the full onMeasure()/layout() cycle. There's no reason that I can see to try to lay out the entire app all over again; nothing has been added or removed, and nothing has changed size that I can see.
The problem tends to happen when the layout is very crowded, and it's possible that the bottom row of buttons has gone beyond the edge of the screen by a pixel or two.
Does anybody have any experience with this? Is there any way to determine why a layout cycle was triggered?
It seems that the layout won't be triggered if none of the TextFields on the screen are modified (see Finding the cause of a layout request in a ViewGroup). Does modifying a TextField always trigger a re-layout? Can I lock it somehow to prevent this? It's frustrating to think that changing any TextField anywhere on the screen can cause a full measure/layout cycle to cascade through the entire app; it's butchering my performance.
The container is a custom ViewGroup class, but I don't think that's the problem. I don't see what I could be doing differently to keep it from being called.
I'm considering adding a "lock" method to my widget to prevent any further layout changes after the initial layout. That will improve performance, but I'd rather solve the underlying problem.
Here's the stack at the time my onMeasure() method is called:
Gridbox.onMeasure(int, int) line: 217
Gridbox(View).measure(int, int) line: 8171
FrameLayout(ViewGroup).measureChildWithMargins(View, int, int, int, int) line: 3132
FrameLayout.onMeasure(int, int) line: 245
FrameLayout(View).measure(int, int) line: 8171
PhoneWindow$DecorView(ViewGroup).measureChildWithMargins(View, int, int, int, int) line: 3132
PhoneWindow$DecorView(FrameLayout).onMeasure(int, int) line: 245
PhoneWindow$DecorView(View).measure(int, int) line: 8171
ViewRoot.performTraversals() line: 801
ViewRoot.handleMessage(Message) line: 1727
ViewRoot(Handler).dispatchMessage(Message) line: 99
Looper.loop() line: 123
ActivityThread.main(String[]) line: 4627
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 521
ZygoteInit$MethodAndArgsCaller.run() line: 858
ZygoteInit.main(String[]) line: 616
NativeStart.main(String[]) line: not available [native method]