in litho-core/src/main/java/com/facebook/litho/ComponentTree.java [1111:1224]
void measure(int widthSpec, int heightSpec, int[] measureOutput, boolean forceLayout) {
assertMainThread();
mIsMeasuring = true;
try {
final boolean needsSyncLayout;
synchronized (this) {
if (DEBUG_LOGS) {
debugLog(
"StartMeasure",
"WidthSpec: "
+ View.MeasureSpec.toString(widthSpec)
+ ", HeightSpec: "
+ View.MeasureSpec.toString(heightSpec)
+ ", isCompatibleWithCommittedLayout: "
+ isCompatibleSpec(mCommittedLayoutState, widthSpec, heightSpec)
+ ", isCompatibleWithMainThreadLayout: "
+ isCompatibleComponentAndSpec(
mMainThreadLayoutState,
mRoot != null ? mRoot.getId() : INVALID_ID,
widthSpec,
heightSpec)
+ ", hasSameSpecs: "
+ (mMainThreadLayoutState != null
&& mMainThreadLayoutState.getWidthSpec() == widthSpec
&& mMainThreadLayoutState.getHeightSpec() == heightSpec));
}
if (mCommittedLayoutState != null
&& mCommittedLayoutState != mMainThreadLayoutState
&& isCompatibleSpec(mCommittedLayoutState, widthSpec, heightSpec)) {
promoteCommittedLayoutStateToUI();
}
final boolean hasExactSameSpecs =
mMainThreadLayoutState != null
&& mMainThreadLayoutState.getWidthSpec() == widthSpec
&& mMainThreadLayoutState.getHeightSpec() == heightSpec;
final boolean hasSameRootAndEquivalentSpecs =
isCompatibleComponentAndSpec(
mMainThreadLayoutState,
mRoot != null ? mRoot.getId() : INVALID_ID,
widthSpec,
heightSpec);
if (hasExactSameSpecs || hasSameRootAndEquivalentSpecs) {
measureOutput[0] = mMainThreadLayoutState.getWidth();
measureOutput[1] = mMainThreadLayoutState.getHeight();
needsSyncLayout = false;
} else {
needsSyncLayout = true;
}
}
if (needsSyncLayout || forceLayout) {
final Size output = new Size();
setSizeSpecForMeasure(widthSpec, heightSpec, output, forceLayout);
// It's possible we don't commit a layout or block on a future on another thread (which will
// not immediately promote the committed layout state since that needs to happen on the main
// thread). Ensure we have the latest LayoutState before exiting.
synchronized (this) {
if (mReleased) {
throw new RuntimeException("Tree is released during measure!");
}
if (mCommittedLayoutState != mMainThreadLayoutState) {
promoteCommittedLayoutStateToUI();
}
if (mMainThreadLayoutState != null) {
measureOutput[0] = mMainThreadLayoutState.getWidth();
measureOutput[1] = mMainThreadLayoutState.getHeight();
} else {
measureOutput[0] = output.width;
measureOutput[1] = output.height;
ComponentsReporter.emitMessage(
ComponentsReporter.LogLevel.ERROR,
"NullLayoutStateInMeasure",
"Measure Specs: ["
+ View.MeasureSpec.toString(widthSpec)
+ ", "
+ View.MeasureSpec.toString(heightSpec)
+ "], Current Specs: ["
+ View.MeasureSpec.toString(mWidthSpec)
+ ", "
+ View.MeasureSpec.toString(mHeightSpec)
+ "], Output [W: "
+ output.width
+ ", H:"
+ output.height
+ "], Last Layout Source: "
+ LayoutState.layoutSourceToString(mLastLayoutSource));
}
}
} else {
setSizeSpecForMeasureAsync(widthSpec, heightSpec);
}
} finally {
mIsMeasuring = false;
}
if (DEBUG_LOGS) {
debugLog(
"FinishMeasure",
"WidthSpec: "
+ View.MeasureSpec.toString(widthSpec)
+ ", HeightSpec: "
+ View.MeasureSpec.toString(heightSpec)
+ ", OutWidth: "
+ measureOutput[0]
+ ", OutHeight: "
+ measureOutput[1]);
}
}