in litho-core/src/main/java/com/facebook/litho/LayoutState.java [1109:1293]
static LayoutState calculate(
ComponentContext c,
Component component,
@Nullable LayoutStateFuture layoutStateFuture,
StateHandler stateHandler,
int componentTreeId,
int widthSpec,
int heightSpec,
int layoutVersion,
boolean shouldGenerateDiffTree,
@Nullable LayoutState currentLayoutState,
@CalculateLayoutSource int source,
@Nullable String extraAttribution) {
final ComponentsLogger logger = c.getLogger();
final boolean isTracing = ComponentsSystrace.isTracing();
if (isTracing) {
if (extraAttribution != null) {
ComponentsSystrace.beginSection("extra:" + extraAttribution);
}
ComponentsSystrace.beginSectionWithArgs(
new StringBuilder("LayoutState.calculate_")
.append(component.getSimpleName())
.append("_")
.append(layoutSourceToString(source))
.toString())
.arg("treeId", componentTreeId)
.arg("rootId", component.getId())
.arg("widthSpec", SizeSpec.toString(widthSpec))
.arg("heightSpec", SizeSpec.toString(heightSpec))
.flush();
}
final @Nullable DiffNode diffTreeRoot;
final @Nullable LithoNode currentRoot;
final @Nullable LayoutStateContext currentLayoutStateContext;
final boolean isReconcilable;
if (currentLayoutState != null) {
synchronized (currentLayoutState) {
diffTreeRoot = currentLayoutState.mDiffTreeRoot;
currentRoot = currentLayoutState.mRoot;
currentLayoutStateContext = currentLayoutState.getLayoutStateContext();
isReconcilable =
isReconcilable(c, component, Preconditions.checkNotNull(stateHandler), currentRoot);
if (!isReconcilable) { // Release the current InternalNode tree if it is not reconcilable.
currentLayoutState.mRoot = null;
currentLayoutState.mLayoutResult = null;
}
}
} else {
diffTreeRoot = null;
currentRoot = null;
currentLayoutStateContext = null;
isReconcilable = false;
}
final LayoutState layoutState;
final LayoutStateContext layoutStateContext;
try {
final PerfEvent logLayoutState =
logger != null
? LogTreePopulator.populatePerfEventFromLogger(
c, logger, logger.newPerformanceEvent(c, EVENT_CALCULATE_LAYOUT_STATE))
: null;
if (logLayoutState != null) {
logLayoutState.markerAnnotate(PARAM_COMPONENT, component.getSimpleName());
logLayoutState.markerAnnotate(PARAM_LAYOUT_STATE_SOURCE, layoutSourceToString(source));
logLayoutState.markerAnnotate(PARAM_IS_BACKGROUND_LAYOUT, !ThreadUtils.isMainThread());
logLayoutState.markerAnnotate(PARAM_TREE_DIFF_ENABLED, diffTreeRoot != null);
logLayoutState.markerAnnotate(PARAM_ATTRIBUTION, extraAttribution);
logLayoutState.markerAnnotate(PARAM_LAYOUT_VERSION, layoutVersion);
}
layoutState =
new LayoutState(
c, component, stateHandler, layoutStateFuture, currentLayoutState, diffTreeRoot);
layoutStateContext = layoutState.getLayoutStateContext();
if (logLayoutState != null) {
layoutStateContext.setPerfEvent(logLayoutState);
}
// Detect errors internal to components
Component.markLayoutStarted(component, layoutStateContext);
final LithoNode layoutCreatedInWillRender =
component.consumeLayoutCreatedInWillRender(currentLayoutStateContext, c);
c.setLayoutStateContext(layoutStateContext);
layoutState.mShouldGenerateDiffTree = shouldGenerateDiffTree;
layoutState.mComponentTreeId = componentTreeId;
layoutState.mLayoutVersion = layoutVersion;
layoutState.mAccessibilityManager =
(AccessibilityManager) c.getAndroidContext().getSystemService(ACCESSIBILITY_SERVICE);
layoutState.mAccessibilityEnabled =
AccessibilityUtils.isAccessibilityEnabled(layoutState.mAccessibilityManager);
layoutState.mWidthSpec = widthSpec;
layoutState.mHeightSpec = heightSpec;
layoutState.mRootComponentName = component.getSimpleName();
layoutState.mIsCreateLayoutInProgress = true;
final @Nullable LithoLayoutResult root;
if (layoutCreatedInWillRender == null) {
final LayoutResultHolder holder =
Layout.createAndMeasureComponent(
layoutStateContext,
c,
component,
isReconcilable
? Preconditions.checkNotNull(currentRoot).getHeadComponentKey()
: null,
widthSpec,
heightSpec,
isReconcilable,
currentRoot,
diffTreeRoot,
logLayoutState);
// Check if layout was interrupted.
if (holder.wasLayoutInterrupted()) {
layoutState.mPartiallyResolvedRoot =
Preconditions.checkNotNull(holder.mPartiallyResolvedLayout);
layoutState.mRootTransitionId = getTransitionIdForNode(holder.mPartiallyResolvedLayout);
layoutState.mIsCreateLayoutInProgress = false;
layoutState.mIsPartialLayoutState = true;
if (logLayoutState != null) {
Preconditions.checkNotNull(logger).logPerfEvent(logLayoutState);
}
return layoutState;
} else {
root = holder.mResult;
}
} else {
root =
Layout.measure(
layoutStateContext,
c,
layoutCreatedInWillRender,
widthSpec,
heightSpec,
diffTreeRoot);
}
final @Nullable LithoNode node = root != null ? root.getNode() : null;
layoutState.mLayoutResult = root;
layoutState.mRoot = node;
layoutState.mRootTransitionId = getTransitionIdForNode(node);
layoutState.mIsCreateLayoutInProgress = false;
if (logLayoutState != null) {
logLayoutState.markerPoint("start_collect_results");
}
setSizeAfterMeasureAndCollectResults(c, layoutState);
layoutStateContext.releaseReference();
if (logLayoutState != null) {
logLayoutState.markerPoint("end_collect_results");
Preconditions.checkNotNull(logger).logPerfEvent(logLayoutState);
}
} finally {
if (isTracing) {
ComponentsSystrace.endSection();
if (extraAttribution != null) {
ComponentsSystrace.endSection();
}
}
}
LithoStats.incrementComponentCalculateLayoutCount();
if (ThreadUtils.isMainThread()) {
LithoStats.incrementComponentCalculateLayoutOnUICount();
}
return layoutState;
}