/** * For testing purposes, props are only compared if both subcomponents supply them. Otherwise, * just ignore them. */ private static boolean arePropsEqual(Component thatComponent, Component thisComponent) { return thatComponent == null || thisComponent == null || thatComponent.isEquivalentTo(thisComponent); }
@Override public String getName() { return mComponent.getSimpleName(); }
/** * @return whether the given component will render because it returns non-null from its resolved * onCreateLayout, based on its current props and state. Returns true if the resolved layout * is non-null, otherwise false. * @deprecated Using willRender is regarded as an anti-pattern, since it will load all classes * into memory in order to potentially decide not to use any of them. */ @Deprecated public static boolean willRender(ComponentContext c, Component component) { if (component == null) { return false; } final ComponentContext scopedContext = component.getScopedContext(); if (scopedContext != null) { assertSameBaseContext(scopedContext, c); } if (component.mLayoutCreatedInWillRender != null) { return willRender(component.mLayoutCreatedInWillRender); } component.mLayoutCreatedInWillRender = Layout.create(c, component); return willRender(component.mLayoutCreatedInWillRender); }
static boolean isLayoutSpecWithSizeSpec(@Nullable Component component) { return (isLayoutSpec(component) && component.canMeasure()); }
/** * Only use if absolutely needed! This removes the cached layout so this component will be * remeasured even if it has alread been measured with the same size specs. */ public void releaseCachedLayout() { final InternalNode cachedLayout = getCachedLayout(); if (cachedLayout != null) { LayoutState.releaseNodeTree(cachedLayout, true /* isNestedTree */); clearCachedLayout(); } }
InternalNode resolveLayout(Component component) { final InternalNode layoutCreatedInWillRender = component.consumeLayoutCreatedInWillRender(); if (layoutCreatedInWillRender != null) { return layoutCreatedInWillRender; } component = component.getThreadSafeInstance(); component.updateInternalChildState(this, true); if (ComponentsConfiguration.isDebugModeEnabled) { DebugComponent.applyOverrides(this, component); } final InternalNode node = (InternalNode) component.resolve(component.getScopedContext()); if (component.canResolve()) { final CommonPropsCopyable props = component.getCommonPropsCopyable(); if (props != null) { props.copyInto(component.getScopedContext(), node); } } return node; }
componentSpy.measure( c, widthMeasuredComponent, doReturn(componentSpy).when(componentSpy).makeShallowCopy(); assertThat(componentSpy.getCachedLayout()).isNotNull(); final InternalNode cachedLayout = componentSpy.getCachedLayout(); assertThat(cachedLayout.getChildCount()).isEqualTo(0); assertThat(cachedLayout.getRootComponent()).isInstanceOf(TestDrawableComponent.class); heightSpec); verify(componentSpy, times(1)).makeShallowCopy(); verify(componentSpy, never()).releaseCachedLayout(); verify(componentSpy, times(1)).clearCachedLayout();
@Test public void testCreateLayoutWithNullComponentWithMountSpecCannotMeasure() { Component component = setUpSpyLayoutSpecWithNullLayout(); component.createLayout(mContext, false); verify(component).onCreateLayout(mContext); verify(component, never()).onPrepare(mContext); }
final InternalNode layoutCreatedInWillRender = component.consumeLayoutCreatedInWillRender(); Component.isNestedTree((Component) this) && !resolveNestedTree; ComponentsSystrace.beginSection("createLayout:" + ((Component) this).getSimpleName()); node = ComponentsPools.acquireInternalNode(context); node.markIsNestedTreeHolder(context.getTreeProps()); } else if (component.canResolve()) { context.setTreeProps(component.getScopedContext().getTreePropsCopy()); node = (InternalNode) component.resolve(context); } else { final Component layoutComponent = createComponentLayout(context); if (layoutComponent == null || layoutComponent.getId() <= 0) { node = null; } else { final CommonPropsCopyable commonProps = ((Component) this).getCommonPropsCopyable(); if (commonProps != null && (deferNestedTreeResolution || !Component.isLayoutSpecWithSizeSpec((Component) this))) { commonProps.copyInto(context, node); && Component.isMountSpec((Component) this);
ComponentsSystrace.beginSectionWithArgs("measure:" + component.getSimpleName()) .arg("widthSpec", SizeSpec.toString(widthSpec)) .arg("heightSpec", SizeSpec.toString(heightSpec)) .arg("componentId", component.getId()) .flush(); int outputHeight = 0; if (Component.isNestedTree(component) || node.hasNestedTree()) { ComponentsLogger.LogLevel.ERROR, "component " + component.getSimpleName() + " is a nested tree but does not have a parent component." + "[mGlobalKey:" + component.getGlobalKey() + "]"); && diffNode.getLastWidthSpec() == widthSpec && diffNode.getLastHeightSpec() == heightSpec && !component.shouldAlwaysRemeasure()) { outputWidth = (int) diffNode.getLastMeasuredWidth(); outputHeight = (int) diffNode.getLastMeasuredHeight(); component.onMeasure(component.getScopedContext(), node, widthSpec, heightSpec, size);
final boolean isTracing = ComponentsSystrace.isTracing(); if (isTracing) { ComponentsSystrace.beginSection("collectResults:" + component.getSimpleName()); ComponentsSystrace.beginSectionWithArgs("resolveNestedTree:" + component.getSimpleName()) .arg("widthSpec", "EXACTLY " + node.getWidth()) .arg("heightSpec", "EXACTLY " + node.getHeight()) .arg("rootComponentId", node.getRootComponent().getId()) .flush(); final DiffNode currentDiffNode = node.getDiffNode(); final boolean shouldUseCachedOutputs = isMountSpec(component) && currentDiffNode != null; final boolean isCachedOutputUpdated = shouldUseCachedOutputs && node.areCachedMeasuresValid(); if (shouldGenerateDiffTree) { if (isTracing) { ComponentsSystrace.beginSection("createDiffNode:" + component.getSimpleName()); ComponentsSystrace.beginSection("addBgDrawableComponent:" + component.getSimpleName()); if (isMountSpec(component)) { ComponentsSystrace.beginSection("onBoundsDefined:" + component.getSimpleName()); component.onBoundsDefined(layoutState.mContext, node); if (isTracing) { ComponentsSystrace.endSection();
InternalNode newLayoutBuilder( Component component, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { final InternalNode layoutCreatedInWillRender = component.consumeLayoutCreatedInWillRender(); if (layoutCreatedInWillRender != null) { return layoutCreatedInWillRender; } component = component.getThreadSafeInstance(); component.updateInternalChildState(this); if (ComponentsConfiguration.isDebugModeEnabled) { DebugComponent.applyOverrides(this, component); } final InternalNode node = component.createLayout(component.getScopedContext(), false); if (node != NULL_LAYOUT) { applyStyle(node, defStyleAttr, defStyleRes); } return node; }
private void checkIsDuplicateKey(Component component) { if (mKnownGlobalKeys.contains(component.getGlobalKey())) { final String message = "Found another " + component.getSimpleName() + " Component with the same key: " + component.getKey(); final String errorMessage = mLogger == null ? message : getDuplicateKeyMessage(); if (component.hasState()) { throw new RuntimeException(message + "\n" + errorMessage); } if (mLogger != null) { mLogger.emitMessage(ComponentsLogger.LogLevel.ERROR, message + "\n" + errorMessage); } } }
private String generateKey(ComponentContext parentContext) { final Component parentScope = parentContext.getComponentScope(); final String key = getKey(); final String globalKey; if (parentScope == null) { globalKey = key; } else { if (parentScope.getGlobalKey() == null) { final ComponentsLogger logger = parentContext.getLogger(); if (logger != null) { logger.emitMessage( ComponentsLogger.LogLevel.ERROR, "Trying to generate parent-based key for component " + getSimpleName() + " , but parent " + parentScope.getSimpleName() + " has a null global key \"." + " This is most likely a configuration mistake, check the value of ComponentsConfiguration.useGlobalKeys."); } globalKey = "null" + key; } else { globalKey = parentScope.generateUniqueGlobalKeyForChild(this, key); } } return globalKey; }
maybeInitNeededStateContainers(); if (!component.hasState()) { return; final String key = component.getGlobalKey(); final StateContainer currentStateContainer; component.transferState(currentStateContainer, component.getStateContainer()); } else { component.createInitialState(component.getScopedContext()); update.updateState(component.getStateContainer()); if (component.getScopedContext().isNestedTreeResolutionExperimentEnabled()) { synchronized (this) { final StateContainer stateContainer = component.getStateContainer(); mStateContainers.put(key, stateContainer); if (stateContainer instanceof ComponentLifecycle.TransitionContainer) {
private void recordRenderData(Component component) { if (!component.needsPreviousRenderData()) { throw new RuntimeException( "Trying to record previous render data for component that doesn't support it"); } final String key = component.getGlobalKey(); // Sanity check like in StateHandler if (mSeenGlobalKeys.contains(key)) { // We found two components with the same global key. throw new RuntimeException( "Cannot record previous render data for " + component.getSimpleName() + ", found another Component with the same key: " + key); } mSeenGlobalKeys.add(key); final ComponentLifecycle.RenderData existingInfo = mRenderData.get(key); final ComponentLifecycle.RenderData newInfo = component.recordRenderData(existingInfo); mRenderData.put(key, newInfo); }
/** * Assert that a given {@link Component} produces a layout that's not equivalent to {@link * ComponentContext#NULL_LAYOUT}. */ public ComponentAssert willRender() { Java6Assertions.assertThat(Component.willRender(mComponentContext, actual)) .overridingErrorMessage("Expected Component to not render to null, but it did.") .isTrue(); return this; }
@Test public void testCreateLayoutAndDontResolveNestedTreeWithLayoutSpecCanMeasure() { Component component = setUpSpyComponentForCreateLayout( false /* isMountSpec */, true /* canMeasure */); component.createLayout(mContext, false); PowerMockito.verifyStatic(); // Calling here to verify static call. ComponentsPools.acquireInternalNode(mContext); verify(component, never()).onCreateLayout( any(ComponentContext.class)); verify(component, never()).onCreateLayoutWithSizeSpec( any(ComponentContext.class), anyInt(), anyInt()); verify(mNode).appendComponent(component); verify(mNode).setMeasureFunction(any(YogaMeasureFunction.class)); verify(component, never()) .onPrepare(any(ComponentContext.class)); }
@Test public void testCreateLayoutUsesWillRenderResult() { ComponentContext c = new ComponentContext(application); final Component component = TestLayoutComponent.create(c, 0, 0, true, true, true, false).build(); Component.willRender(c, component); final InternalNode cachedLayout = component.getLayoutCreatedInWillRenderForTesting(); assertThat(cachedLayout).isNotNull(); InternalNode result = component.createLayout(c, false); assertThat(result).isEqualTo(cachedLayout); assertThat(component.getLayoutCreatedInWillRenderForTesting()).isNull(); }
@Test public void testWillRenderTwiceDoesNotReCreateLayout() { ComponentContext c = new ComponentContext(application); final Component component = TestLayoutComponent.create(c, 0, 0, true, true, true, false).build(); Component.willRender(c, component); final InternalNode cachedLayout = component.getLayoutCreatedInWillRenderForTesting(); assertThat(cachedLayout).isNotNull(); assertThat(Component.willRender(c, component)).isTrue(); assertThat(component.getLayoutCreatedInWillRenderForTesting()).isEqualTo(cachedLayout); }