Home » Android » android – Why view.onLayout() is called repetitively when changed=false?

android – Why view.onLayout() is called repetitively when changed=false?

Posted by: admin June 15, 2020 Leave a comment

Questions:

From the official docs:

Android Docs – View

protected void onLayout (boolean changed, int left, int top, int right, int bottom)

Parameters
changed This is a new size or position for this view
left    Left position, relative to parent
top     Top position, relative to parent
right   Right position, relative to parent
bottom  Bottom position, relative to parent 

Why my custom view is called repetitively with changed=false? Is it normal?

Here’s the call tree:

Synoptic.onLayout(boolean, int, int, int, int) line: 130    
Synoptic(View).layout(int, int, int, int) line: 11282   
Synoptic(ViewGroup).layout(int, int, int, int) line: 4224   
RelativeLayout.onLayout(boolean, int, int, int, int) line: 925  
RelativeLayout(View).layout(int, int, int, int) line: 11282 
RelativeLayout(ViewGroup).layout(int, int, int, int) line: 4224 
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutHorizontal() line: 1617  
LinearLayout.onLayout(boolean, int, int, int, int) line: 1401   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
SwipeView(FrameLayout).onLayout(boolean, int, int, int, int) line: 431  
SwipeView(HorizontalScrollView).onLayout(boolean, int, int, int, int) line: 1382    
SwipeView.onLayout(boolean, int, int, int, int) line: 154   
SwipeView(View).layout(int, int, int, int) line: 11282  
SwipeView(ViewGroup).layout(int, int, int, int) line: 4224  
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutVertical() line: 1486    
LinearLayout.onLayout(boolean, int, int, int, int) line: 1399   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
FrameLayout.onLayout(boolean, int, int, int, int) line: 431 
FrameLayout(View).layout(int, int, int, int) line: 11282    
FrameLayout(ViewGroup).layout(int, int, int, int) line: 4224    
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutVertical() line: 1486    
LinearLayout.onLayout(boolean, int, int, int, int) line: 1399   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
PhoneWindow$DecorView(FrameLayout).onLayout(boolean, int, int, int, int) line: 431  
PhoneWindow$DecorView(View).layout(int, int, int, int) line: 11282  
PhoneWindow$DecorView(ViewGroup).layout(int, int, int, int) line: 4224  
ViewRootImpl.performTraversals() line: 1514 
ViewRootImpl.handleMessage(Message) line: 2467  
ViewRootImpl(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 137 
ActivityThread.main(String[]) line: 4424    
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
Method.invoke(Object, Object...) line: 511  
ZygoteInit$MethodAndArgsCaller.run() line: 784  
ZygoteInit.main(String[]) line: 551 
NativeStart.main(String[]) line: not available [native method]  
How to&Answers:

The key part here from the docs is:

Called from layout when this view should assign a size and position to each of its children.

If a View inside a ViewGroup is set to wrap_content and it changes its size (e.g. the text inside a TextView changes to a longer string) then an onLayout in the ViewGroup will occur. This is because Views are given their size when laid out, so without the call the View will never be given a new size.

Answer:

I found the problem: for a compound component like mine, that contains a TextView, the repetitive call to .setText() causes a call to the parent’s onLayout()

…even if the new text is equal to the current TextView text!

so I solved:

public void setTextViewText(String text) {
    if (!this.textViewValue.getText().equals(text)) {
        this.textViewValue.setText(text);
    }
}