in litho-core/src/main/java/com/facebook/litho/ComponentTree.java [2099:2245]
private void setRootAndSizeSpecInternal(
@Nullable Component root,
int widthSpec,
int heightSpec,
boolean isAsync,
@Nullable Size output,
@CalculateLayoutSource int source,
int externalRootVersion,
@Nullable String extraAttribution,
@Nullable TreeProps treeProps,
boolean isCreateLayoutInProgress,
boolean forceLayout) {
synchronized (this) {
if (mReleased) {
// If this is coming from a background thread, we may have been released from the main
// thread. In that case, do nothing.
//
// NB: This is only safe because we don't re-use released ComponentTrees.
return;
}
// If this is coming from a setRoot
if (source == CalculateLayoutSource.SET_ROOT_SYNC
|| source == CalculateLayoutSource.SET_ROOT_ASYNC) {
if (mExternalRootVersion >= 0 && externalRootVersion < 0) {
throw new IllegalStateException(
"Setting an unversioned root after calling setVersionedRootAndSizeSpec is not "
+ "supported. If this ComponentTree takes its version from a parent tree make "
+ "sure to always call setVersionedRootAndSizeSpec");
}
if (mExternalRootVersion > externalRootVersion) {
// Since this layout is not really valid we don't need to set a Size.
return;
}
mExternalRootVersion = externalRootVersion;
}
if (root != null) {
if (mStateHandler != null && mStateHandler.hasUncommittedUpdates()) {
root = root.makeShallowCopyWithNewId();
}
}
final boolean rootInitialized = root != null;
final boolean treePropsInitialized = treeProps != null;
final boolean widthSpecInitialized = widthSpec != SIZE_UNINITIALIZED;
final boolean heightSpecInitialized = heightSpec != SIZE_UNINITIALIZED;
final Component resolvedRoot = root != null ? root : mRoot;
final int resolvedWidthSpec = widthSpecInitialized ? widthSpec : mWidthSpec;
final int resolvedHeightSpec = heightSpecInitialized ? heightSpec : mHeightSpec;
final LayoutState mostRecentLayoutState = mCommittedLayoutState;
if (!forceLayout
&& resolvedRoot != null
&& mostRecentLayoutState != null
&& mostRecentLayoutState.isCompatibleComponentAndSpec(
resolvedRoot.getId(), resolvedWidthSpec, resolvedHeightSpec)) {
// The spec and the root haven't changed and we have a compatible LayoutState already
// committed
if (output != null) {
output.height = mostRecentLayoutState.getHeight();
output.width = mostRecentLayoutState.getWidth();
}
if (DEBUG_LOGS) {
debugLog(
"StartLayout",
"Layout was compatible, not calculating a new one - Source: "
+ layoutSourceToString(source)
+ ", Extra: "
+ extraAttribution
+ ", WidthSpec: "
+ View.MeasureSpec.toString(resolvedWidthSpec)
+ ", HeightSpec: "
+ View.MeasureSpec.toString(resolvedHeightSpec));
}
return;
}
if (DEBUG_LOGS) {
debugLog(
"StartLayout",
"Calculating new layout - Source: "
+ layoutSourceToString(source)
+ ", Extra: "
+ extraAttribution
+ ", WidthSpec: "
+ View.MeasureSpec.toString(resolvedWidthSpec)
+ ", HeightSpec: "
+ View.MeasureSpec.toString(resolvedHeightSpec));
}
if (widthSpecInitialized) {
mWidthSpec = widthSpec;
}
if (heightSpecInitialized) {
mHeightSpec = heightSpec;
}
if (rootInitialized) {
mRoot = root;
}
if (forceLayout && mRoot != null) {
mRoot = mRoot.makeShallowCopyWithNewId();
}
if (treePropsInitialized) {
mRootTreeProps = treeProps;
} else {
treeProps = mRootTreeProps;
}
mLastLayoutSource = source;
}
if (isAsync && output != null) {
throw new IllegalArgumentException(
"The layout can't be calculated asynchronously if we need the Size back");
}
if (isAsync) {
synchronized (mCurrentCalculateLayoutRunnableLock) {
if (mCurrentCalculateLayoutRunnable != null) {
mLayoutThreadHandler.remove(mCurrentCalculateLayoutRunnable);
}
mCurrentCalculateLayoutRunnable =
new CalculateLayoutRunnable(
source, treeProps, extraAttribution, isCreateLayoutInProgress);
String tag = EMPTY_STRING;
if (mLayoutThreadHandler.isTracing()) {
tag = "calculateLayout ";
if (root != null) {
tag = tag + root.getSimpleName();
}
}
mLayoutThreadHandler.post(mCurrentCalculateLayoutRunnable, tag);
}
} else {
calculateLayout(output, source, extraAttribution, treeProps, isCreateLayoutInProgress);
}
}