224

I'm a bit confused about the roles of forceLayout(), requestLayout() and invalidate() methods of the View class.

When shall they be called?

sdabet
  • 18,360
  • 11
  • 89
  • 158

6 Answers6

415

To better understand answers provided by François BOURLIEUX and Dalvik I suggest you take a look at this awesome view lifecycle diagram by Arpit Mathur: enter image description here

Community
  • 1
  • 1
Bartek Lipinski
  • 30,698
  • 10
  • 94
  • 132
  • 30
    I often see requestLayout being called directly after invalidate is called, I even see that happening in Android source code for things like TextView, but according to this diagram doing so is redundant, right? So is there any purpose for doing that? – tcox May 12 '15 at 22:10
  • 5
    Well that's an interesting question, and to be honest I don't really know why they call both methods in e.g. `TextView`. I thought that maybe they want to draw the `View` for the last time before they change its layout-related parameters, but it doesn't really make any sense if we think about those calls being invoked in the different order (and they call `invalidate()` right after `requestLayout()` in `TextView` as well). Maybe it deserves another question on StackOverflow :)? – Bartek Lipinski May 15 '15 at 09:21
  • Just to note that the diagram above is clean but might be misleading. I believe that invalidate() also might schedule a MEASURE pass over the view hierarchy ( using ViewRoot ). If the visual change is a simple bg color change, then we have nothing to worry about MEASURE pass or performance. But the invalidation reason is a size change for example, then MEASURE pass also supposed to be kicked off and rendering pipeline steps should be very much alike ( or exactly the same) as with requestLayout's. – stdout Jun 15 '16 at 12:47
  • 23
    **(1/2)**: I don't think you understand those two methods (`invalidate()` and `requestLayout()`) properly. The purpose of those methods is to tell the `View` what sort of *invalidation* (as you called it) has happened. It's not like the `View` decides what path to follow after you call one of those methods. The logic behind choosing the `View`-lifecycle-path is the choosing of the proper method to call itself. If there's something related to size change - `requestLayout()` should be called, if there's only a visual change without a size changed - you should call `invalidate()`. – Bartek Lipinski Jun 15 '16 at 13:54
  • 17
    **(2/2):** If you change the size of your `View` in some way, e.g. you **get current `LayoutParams`** of a `View` and you modify them, but **NOT** call either `requestLayout` or `setLayoutParams` (which calls `requestLayout` internally), then you can call `invalidate()` as much as you want, and the `View` will not go through the measure-layout process, therefore will not change its size. If you don't tell your `View` that its size has changed (with a `requestLayout` method call), then the `View` will assume it didn't, and the `onMeasure` and `onLayout` won't be called. – Bartek Lipinski Jun 15 '16 at 13:58
  • 2
    @tcox more here --> http://stackoverflow.com/questions/35279374/why-is-requestlayout-being-called-directly-after-invalidate/40402309#40402309 – Sotti Nov 03 '16 at 13:09
  • 1
    This diagram is misleading. See [here](http://grokbase.com/p/gg/android-developers/12amz5pqv8/does-an-ondraw-get-called-if-i-dont-do-invalidate-but-did-the-requestlayout) and [here](http://stackoverflow.com/a/42430021/3681880). Calling `requestLayout()` is not guaranteed to result in an `onDraw`. – Suragch Feb 24 '17 at 03:05
  • Hey @BartekLipinski can you please help me with this https://stackoverflow.com/questions/49952965/recyclerview-horizontal-scrolling-to-left –  May 18 '18 at 11:27
167

invalidate()

Calling invalidate() is done when you want to schedule a redraw of the view. It will result in onDraw being called eventually (soon, but not immediately). An example of when a custom view would call it is when a text or background color property has changed.

The view will be redrawn but the size will not change.

requestLayout()

If something about your view changes that will affect the size, then you should call requestLayout(). This will trigger onMeasure and onLayout not only for this view but all the way up the line for the parent views.

Calling requestLayout() is not guaranteed to result in an onDraw (contrary to what the diagram in the accepted answer implies), so it is usually combined with invalidate().

invalidate();
requestLayout();

An example of this is when a custom label has its text property changed. The label would change size and thus need to be remeasured and redrawn.

forceLayout()

When there is a requestLayout() that is called on a parent view group, it does not necessary need to remeasure and relayout its child views. However, if a child should be included in the remeasure and relayout, then you can call forceLayout() on the child. forceLayout() only works on a child if it occurs in conjunction with a requestLayout() on its direct parent. Calling forceLayout() by itself will have no effect since it does not trigger a requestLayout() up the view tree.

Read this Q&A for a more detailed description of forceLayout().

Further study

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • 1
    but wouldn't it then make more sense to first call requestLayout() and then invalidate() ? – scholt Aug 23 '19 at 14:46
  • 3
    @scholt, As far as I know the order doesn't matter, so you can call `requestLayout()` before `invalidate()` if you want. Neither one does a layout or draw immediately. Rather, they set flags that will eventually result in a relayout and redraw. – Suragch Aug 24 '19 at 06:37
30

Here you can find some response: http://developer.android.com/guide/topics/ui/how-android-draws.html

For me a call to invalidate() only refreshes the view and a call to requestLayout() refreshes the view and compute the size of the view on the screen.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • 4
    how about forceLayout() then ? – sdabet Dec 13 '12 at 11:58
  • @fiddler , this method just sets two flags: PFLAG_FORCE_LAYOUT and PFLAG_INVALIDATED – suitianshi Jan 24 '14 at 03:19
  • 9
    @suitianshi What are the consequences of setting the flags then? – Sergey May 15 '15 at 11:55
  • 1
    @Sergey The consequence seems to be that this flag overrides measure cache (views use cache to measure faster in the future for the same MeasureSpec); see line 18783 of View.java here: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java – RhetoricalRuvim May 25 '16 at 19:35
5

invalidate() ---> onDraw() from UI thread

postInvalidate() ---> onDraw() from background thread

requestLayout() ---> onMeasure() and onLayout() AND NOT Necessarily onDraw()

  • IMPORTANT: Calling this method does not affect the called class's child.

forceLayout() ---> onMeasure() and onLayout() JUST IF the direct parent called requestLayout().

Ehsan Mashhadi
  • 2,568
  • 1
  • 19
  • 30
  • The following is incorrect or should be explained better. "postInvalidate() ---> onDraw() from background thread". It triggers onDraw on the next UI thread draw cycle. Also, you can call postInvalidate() from a background thread. – Jona Feb 18 '21 at 14:45
3

you use invalidate() on a view that you want to redraw, it'll make its onDraw(Canvas c) to invoked, and requestLayout() will make the whole layout rendering ( measurement phase and positioning phase) run again. You should use it if you are changing child view's size on runtime but only in particular cases like constraints from the parent view(by that I mean that the parent height or width are WRAP_CONTENT and so match measure the children before they can wrap them again)

Nativ
  • 3,092
  • 6
  • 38
  • 69
3

This answer is not correct about forceLayout().

As you can see in the code of forceLayout() it merely marks the view as "needs a relayout" but it does neither schedule nor trigger that relayout. The relayout will not happen until at some point in the future the view's parent was laid out for some other reason.

There is also a much bigger issue when using forceLayout() and requestLayout():

Let's say you've called forceLayout() on a view. Now when calling requestLayout() on a descendent of that view, Android will recursively call requestLayout() on that descendent's ancestors. The problem is that it will stop the recursion at the view on which you've called forceLayout(). So the requestLayout() call will never reach the view root and thus never schedule a layout pass. An entire subtree of the view hierarchy is waiting for a layout and calling requestLayout() on any view of that subtree will not cause a layout. Only calling requestLayout() on any view outside that subtree will break the spell.

I'd consider the implementation of forceLayout() (and how it affects requestLayout() to be broken and you should never use that function in your code.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
fluidsonic
  • 4,655
  • 2
  • 24
  • 34
  • 1
    Hi! How have you come up with that *spell*? Is that documented somewhere? – azizbekian Jun 27 '17 at 13:31
  • 1
    Unfortunately it's not documented and likely not even intended. I figured that out by investigating the code of `View` and by running into the issue myself & debugging it. – fluidsonic Jun 27 '17 at 13:49
  • Then I'm curious about the purpose of `forceLayout()` API: it doesn't actually force a layout pass, rather it just changes a flag [which is being observed in `onMeasure()`](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/view/View.java#19834), but `onMeasure()` won't be called unless `requestLayout()` or an explicit `View#measure()` is called. That means, that `forceLayout()` should be paired with `requestLayout()`. On the other hand, why then to perform `forceLayout()` if I still need to perform `requestLayout()`? – azizbekian Jun 27 '17 at 14:48
  • @azizbekian no, you don't have to. `requestLayout()` does everything which `forceLayout()` also does. – fluidsonic Jun 27 '17 at 20:26
  • See [this answer](https://stackoverflow.com/a/45969662/3681880) for how `forceLayout` might appropriately be used in code. – Suragch Oct 20 '17 at 03:33
  • 1
    @Suragch missed that one, thanks! Very interesting analysis. The intended use of `forceLayout` makes sense. So in the end it's just very badly named and documented. – fluidsonic Oct 20 '17 at 19:19