This article was translated from Japanese by Claude Code.

I found an API with a fun name called setLayoutFrozen/isLayoutFrozen, so here’s a memo about it.
I found it while implementing a screen using CoordinatorLayout + RecyclerView at work. When the screen launched, the RecyclerView would unintentionally scroll slightly, and I couldn’t pin down the cause. While searching for how to fix it, including temporary workarounds, I discovered this property. (I still don’t know the root cause. If anyone knows, I’d appreciate if you could tell me π)
β»In my case, freezing the layout just because of unintended scrolling isn’t a fundamental solution, but if you absolutely need to limit layout processing or scrolling due to user touch events, maybe you could use this API.
Note that the RecyclerView source code version referenced in this article is androidx.recyclerview:recyclerview:1.0.0.
mLayoutFrozen#
Inside the RecyclerView class, a field is defined like this:
boolean mLayoutFrozen;The setLayoutFrozen API is used to toggle the true/false value of this mLayoutFrozen. mLayoutFrozen is referenced in various places both in public APIs of RecyclerView and in internal logic. For example, RecyclerView has a scrollToPosition API for scrolling to a specific position, and mLayoutFrozen is also referenced inside this function.
public void scrollToPosition(int position) {
if (mLayoutFrozen) {
return;
}
...
}As shown above, a guard clause is written where if the value of mLayoutFrozen is true, it returns without doing any scrolling. This way, by using the setLayoutFrozen API to toggle this property’s value, you can control layout processing and scrolling that would normally occur inside RecyclerView.
setLayoutFrozen(true / false)#
As the name suggests, it’s an API that specifies whether to freeze layout. True freezes it, false unfreezes it. When frozen, RecyclerView’s layout processing and scrolling won’t occur until you unfreeze.
This function cannot be called while RecyclerView is updating layout or scrolling. Inside the setLayoutFrozen function, it first checks whether RecyclerView is currently performing layout or scroll processing, and if any processing is happening, an IllegalStateException is thrown. I don’t fully understand the exact reason, but I suspect it’s because stopping movement mid-drawing could easily cause unexpected rendering or behavior.
If unfreezing layout:
- Set mLayoutFrozen to false and call requestLayout as needed.
If freezing layout:
- Send an empty touch event to onTouchEvent,
- Set mLayoutFrozen to true,
- Stop scrolling.
Below is the corresponding setLayoutFrozen code:
public void setLayoutFrozen(boolean frozen) {
if (frozen != mLayoutFrozen) {
assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll");
if (!frozen) {
mLayoutFrozen = false;
if (mLayoutWasDefered && mLayout != null && mAdapter != null) {
requestLayout();
}
mLayoutWasDefered = false;
} else {
final long now = SystemClock.uptimeMillis();
MotionEvent cancelEvent = MotionEvent.obtain(
now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
onTouchEvent(cancelEvent);
mLayoutFrozen = true;
mIgnoreMotionEventTillDown = true;
stopScroll();
}
}
}
}isLayoutFrozen#
isLayoutFrozen simply returns the mLayoutFrozen field:
public boolean isLayoutFrozen() {
return mLayoutFrozen;
}By the way#
The unwanted scrolling problem I was facing was solved by setting the RecyclerView’s descendantFocusability to FOCUS_BLOCK_DESCENDANTS based on an Android team member’s idea, preventing unnecessary focus from being applied. (Thank you satoshun π)
I think this is a healthier solution than using setLayoutFrozen.
https://developer.android.com/reference/android/view/ViewGroup#setDescendantFocusability(int)
Summary#
RecyclerView has a setLayoutFrozen API, which allows you to “freeze” RecyclerView and prevent layout processing and scrolling from occurring until you “unfreeze” it.
setLayoutFrozen is restricted from being called while layout or scroll processing is occurring.
mLayoutFrozen is defined inside RecyclerView and referenced from various places in RecyclerView’s internal logic.
When I encounter unfamiliar APIs, I want to take notes in some form so I don’t forget them.
That’s all!