/** * Checks to make sure the main thread layout state is valid (and throws if it's both invalid and * there's no layout requested to make it valid). * @return whether the main thread layout state is ok to use */ private boolean checkMainThreadLayoutStateForIncrementalMount() { if (mComponentTree.getMainThreadLayoutState() != null) { return true; } if (!isLayoutRequested()) { throw new RuntimeException( "Trying to incrementally mount a component with a null main thread LayoutState on a " + "LithoView that hasn't requested layout!"); } return false; }
public void performIncrementalMount() { if (mComponentTree == null || mComponentTree.getMainThreadLayoutState() == null) { return; } if (mComponentTree.isIncrementalMountEnabled()) { mComponentTree.incrementalMountComponent(); } else { throw new IllegalStateException("To perform incremental mounting, you need first to enable" + " it when creating the ComponentTree."); } }
@Nullable public static DebugComponent getRootInstance(@Nullable ComponentTree componentTree) { final LayoutState layoutState = componentTree == null ? null : componentTree.getMainThreadLayoutState(); final InternalNode root = layoutState == null ? null : layoutState.getLayoutRoot(); if (root != null) { final int outerWrapperComponentIndex = Math.max(0, root.getComponents().size() - 1); return DebugComponent.getInstance(root, outerWrapperComponentIndex); } return null; }
/** * Restore a previously saved root layout reference. * * @see #getRootLayoutRef(LithoView) */ @ThreadConfined(ThreadConfined.UI) public static void setRootLayoutRef(final LithoView view, final InternalNodeRef rootLayoutNode) { final ComponentTree componentTree = view.getComponentTree(); final LayoutState mainThreadLayoutState = componentTree != null ? componentTree.getMainThreadLayoutState() : null; if (mainThreadLayoutState != null) { mainThreadLayoutState.mLayoutRoot = rootLayoutNode.mInternalNodeRef; } } }
&& mComponentTree.getMainThreadLayoutState() != null && mComponentTree.getMainThreadLayoutState().mLayoutRoot == null) {
/** * Obtain a reference to a LithoView's internal layout root, if present. This is used to restore a * view's root after it has been freed for testing purposes. * * @see #setRootLayoutRef(LithoView, InternalNodeRef) */ @ThreadConfined(ThreadConfined.UI) @Nullable public static InternalNodeRef getRootLayoutRef(final LithoView view) { final ComponentTree componentTree = view.getComponentTree(); final LayoutState mainThreadLayoutState = componentTree != null ? componentTree.getMainThreadLayoutState() : null; return mainThreadLayoutState != null ? new InternalNodeRef(mainThreadLayoutState.getLayoutRoot()) : null; }
if (mDoMeasureInLayout || mComponentTree.getMainThreadLayoutState() == null) {
@Test public void testMeasureDoesNotComputeLayoutStateWhenSpecsAreExact() { mLithoView = new LithoView(RuntimeEnvironment.application); mLithoView.setComponent(TestDrawableComponent.create(mLithoView.getComponentContext()).build()); mLithoView.measure(makeMeasureSpec(100, EXACTLY), makeMeasureSpec(100, EXACTLY)); assertThat(mLithoView.getMeasuredWidth()).isEqualTo(100); assertThat(mLithoView.getMeasuredHeight()).isEqualTo(100); assertThat(mLithoView.getComponentTree().getMainThreadLayoutState()).isNull(); mLithoView.layout(0, 0, 50, 50); final LayoutState layoutState = mLithoView.getComponentTree().getMainThreadLayoutState(); assertThat(layoutState).isNotNull(); assertThat(layoutState.isCompatibleSize(50, 50)).isTrue(); }
@Test public void testMeasureComputesLayoutStateWhenSpecsAreNotExact() { mLithoView = new LithoView(RuntimeEnvironment.application); mLithoView.setComponent( TestDrawableComponent.create(mLithoView.getComponentContext()).heightPx(100).build()); mLithoView.measure(makeMeasureSpec(100, EXACTLY), makeMeasureSpec(100, AT_MOST)); assertThat(mLithoView.getMeasuredWidth()).isEqualTo(100); assertThat(mLithoView.getMeasuredHeight()).isEqualTo(100); assertThat(mLithoView.getComponentTree().getMainThreadLayoutState()).isNotNull(); }
@Test public void testSetRootAsyncFollowedByMeasureDoesntComputeSyncLayout() { ComponentTree componentTree = ComponentTree.create(mContext, mComponent).build(); componentTree.setLithoView(new LithoView(mContext)); componentTree.measure(mWidthSpec, mHeightSpec, new int[2], false); componentTree.attach(); Component newComponent = TestDrawableComponent.create(mContext).color(1234).build(); componentTree.setRootAsync(newComponent); assertThat(componentTree.getRoot()).isEqualTo(newComponent); componentTree.measure(mWidthSpec, mHeightSpec, new int[2], false); assertThat(componentTree.getMainThreadLayoutState().isForComponentId(mComponent.getId())) .isTrue(); mLayoutThreadShadowLooper.runToEndOfTasks(); assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue(); }
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue() .withFailMessage( assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue();
@Test public void testSetRootAsyncFollowedByNonCompatibleMeasureComputesSyncLayout() { ComponentTree componentTree = ComponentTree.create(mContext, mComponent).build(); componentTree.setLithoView(new LithoView(mContext)); componentTree.measure(mWidthSpec, mHeightSpec, new int[2], false); componentTree.attach(); Component newComponent = TestDrawableComponent.create(mContext).color(1234).build(); componentTree.setRootAsync(newComponent); componentTree.measure(mWidthSpec2, mHeightSpec2, new int[2], false); assertThat(componentTree.getRoot()).isEqualTo(newComponent); assertThat(componentTree.hasCompatibleLayout(mWidthSpec2, mHeightSpec2)).isTrue(); assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue(); // Clear tasks mLayoutThreadShadowLooper.runToEndOfTasks(); }
assertThat(componentTree.getMainThreadLayoutState().isForComponentId(mComponent.getId())) .isTrue(); assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue();
@Test public void testMeasureWithIncompatibleSetRootAsyncThatFinishes() { ComponentTree componentTree = ComponentTree.create(mContext, mComponent).build(); componentTree.setLithoView(new LithoView(mContext)); int widthSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY); int heightSpec1 = SizeSpec.makeSizeSpec(1000, SizeSpec.AT_MOST); int widthSpec2 = SizeSpec.makeSizeSpec(1000, SizeSpec.EXACTLY); int heightSpec2 = SizeSpec.makeSizeSpec(0, SizeSpec.UNSPECIFIED); componentTree.measure(widthSpec2, heightSpec2, new int[2], false); componentTree.attach(); componentTree.measure(widthSpec1, heightSpec1, new int[2], false); Component newComponent = TestDrawableComponent.create(mContext).color(1234).build(); componentTree.setRootAsync(newComponent); runOnBackgroundThreadSync( new Runnable() { @Override public void run() { // "Commit" layout (it will fail since it doesn't have compatible size specs) mLayoutThreadShadowLooper.runToEndOfTasks(); } }); componentTree.measure(widthSpec2, heightSpec2, new int[2], false); assertThat(componentTree.getRoot()).isEqualTo(newComponent); assertThat(componentTree.hasCompatibleLayout(widthSpec2, heightSpec2)).isTrue(); assertThat(componentTree.getMainThreadLayoutState().isForComponentId(newComponent.getId())) .isTrue() .withFailMessage( "The main thread should calculate a new layout synchronously because the async layout will not be used once it completes"); }
@Test public void testSetRootWithTreePropsThenMeasure() { ComponentTree componentTree = create(mContext, mComponent).build(); componentTree.setLithoView(new LithoView(mContext)); componentTree.attach(); final TreeProps treeProps = new TreeProps(); treeProps.put(Object.class, "hello world"); componentTree.setRootAndSizeSpecAsync( TestDrawableComponent.create(mContext).build(), makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY), treeProps); assertThat(componentTree.getBackgroundLayoutState()).isNull(); componentTree.measure(makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY), new int[2], true); final ComponentContext c = getInternalState(componentTree.getMainThreadLayoutState(), "mContext"); assertThat(c.getTreeProps()).isNotNull(); assertThat(c.getTreeProps().get(Object.class)).isEqualTo(treeProps.get(Object.class)); }