22

Can anyone tell me how to fix the following trace:

W/View    (16810): requestLayout() improperly called by 
theme.effects.TopCenterImageView{41dc73f0 V.ED.... ........ 
0,0-480,690 #7f060066 app:id/normal_image} during second 
layout pass: posting in next frame

Here is the code for TopCenterImageView:

public class TopCenterImageView extends ImageView {

public TopCenterImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    setScaleType(ScaleType.MATRIX);
}

public TopCenterImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setScaleType(ScaleType.MATRIX);
}

public TopCenterImageView(Context context) {
    super(context);
    setScaleType(ScaleType.MATRIX);
}

@Override
protected boolean setFrame(int l, int t, int r, int b) {
    if (getDrawable() == null) {
        return super.setFrame(l, t, r, b);
    }
    Matrix matrix = getImageMatrix();
    float scaleFactor = getWidth() / (float) getDrawable().getIntrinsicWidth();
    matrix.setScale(scaleFactor, scaleFactor, 0, 0);
    setImageMatrix(matrix);
    return super.setFrame(l, t, r, b);
}

}
Zword
  • 6,605
  • 3
  • 27
  • 52
Aashir
  • 2,621
  • 4
  • 21
  • 37
  • I just encountered the same issue today and it appears that the View in the log is not the culprit. Do you happen to use ValueAnimator or another Animator class in your code? – Kai Jan 16 '14 at 15:26
  • I don't. All the code simply does is that it fetches an image, blurs it and places it over the original while setting the alpha as the user scrolls. – Aashir Jan 16 '14 at 19:21
  • Hmm... if it's still a problem for you, I guess the only thing left to do is to check UI-thread related code. The problem with my code was that I had called `ValueAnimator.start()` multiple times in rapid succession. And the strangest thing is that I would still see the **"requestLayout() improperly called..."** error even when I removed any UI related code from ValueAnimator. Oh and it seem to only happen on 4.3 devices as well. – Kai Jan 17 '14 at 01:21
  • I only setAlpha to an overlay image. Oh and I had been testing on a 4.3 device. Ill check it out on another. – Aashir Jan 25 '14 at 04:41
  • Do you do that periodically? If so maybe try commenting out all related code and see if the issue persists. – Kai Jan 25 '14 at 06:01
  • I did, it still persists. Been debugging but can't find the source. – Aashir Jan 30 '14 at 10:32
  • I assume that `super.setFrame(l, t, r, b);` calls `requestLayout()` somewhere. Is there a chance you are using setFrame in an asynctask? – Daniel Bo Feb 05 '14 at 14:02
  • 1
    Calling setScaleType() calls requestLayout(), which would be "improper" during a layout pass. You might see this during a layout pass that creates new views, such as a ListView layout. You don't need to worry *too* much about this though, as it just schedules another layout pass. – alanv Feb 12 '14 at 05:18

3 Answers3

18

As seen here, setScaleType will call requestLayout, but the constructor of ImageView already call it before. So it will cause the layout to have multiple requestLayout called, one during the layout pass. It's just a warning because at a small scale, it's not a problem.

You will find some good research in this thread (not the roboguice part though).

Community
  • 1
  • 1
NitroG42
  • 5,336
  • 2
  • 28
  • 32
3

I changed a child views layout params in the onLayout method AFTER calling super.onLayout(); That lead to a recursion:

Childlayout params changed -> parent view onRequestLayout() -> parent view onLayout -> childview params changed -> ...

stoefln
  • 14,498
  • 18
  • 79
  • 138
  • 1
    In a custom `TableLayout` class I created I had the same issue. It did not just show the warning, but also prevented scrolling, if a `EditText` inside my `TableLayout` had the focus. Moving `supoer.onLayout` to the bottom of my `onLayout` method solved it. +1 – Robert P Aug 17 '17 at 09:03
1

Use changed parameter as a change check.

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
    super.onLayout(changed, left, top, right, bottom)
    Log.i(TAG, "onLayout: $changed")
    if (changed) {
        changeDefaultView(size)
    }
}

changed is equal to:

TRUE - when the layout CHANGED in comparison with the previous.

FALSE - when the layout DID NOT change in comparison with the previous.

Dharman
  • 30,962
  • 25
  • 85
  • 135