diff --git a/litho-core/src/main/java/com/facebook/litho/IncrementalMountBinder.java b/litho-core/src/main/java/com/facebook/litho/IncrementalMountBinder.java new file mode 100644 index 00000000000..52ce0a2a961 --- /dev/null +++ b/litho-core/src/main/java/com/facebook/litho/IncrementalMountBinder.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.facebook.litho; + +import android.content.Context; +import androidx.annotation.Nullable; +import com.facebook.rendercore.RenderUnit; + +public class IncrementalMountBinder implements RenderUnit.Binder { + + private boolean isUpdating = false; + + @Override + public boolean shouldUpdate( + final LithoRenderUnit currentValue, + final LithoRenderUnit newValue, + final @Nullable Object currentLayoutData, + final @Nullable Object nextLayoutData) { + isUpdating = true; + return true; + } + + @Override + public void bind( + final Context context, + final Object content, + final LithoRenderUnit lithoRenderUnit, + final @Nullable Object layoutData) { + if (!isUpdating) { + return; + } + + isUpdating = false; + + final LayoutOutput output = lithoRenderUnit.output; + final Component component = output.getComponent(); + + IncrementalMountExtension.onItemUpdated(content, component); + } + + @Override + public void unbind( + final Context context, + final Object o, + final LithoRenderUnit lithoRenderUnit, + final @Nullable Object layoutData) {} +} diff --git a/litho-core/src/main/java/com/facebook/litho/IncrementalMountExtension.java b/litho-core/src/main/java/com/facebook/litho/IncrementalMountExtension.java index 16433122781..93291d6ab49 100644 --- a/litho-core/src/main/java/com/facebook/litho/IncrementalMountExtension.java +++ b/litho-core/src/main/java/com/facebook/litho/IncrementalMountExtension.java @@ -20,7 +20,6 @@ import static com.facebook.litho.LayoutOutput.getLayoutOutput; import static com.facebook.litho.ThreadUtils.assertMainThread; -import android.content.Context; import android.graphics.Rect; import android.util.LongSparseArray; import android.view.View; @@ -30,79 +29,26 @@ import com.facebook.litho.stats.LithoStats; import com.facebook.rendercore.Host; import com.facebook.rendercore.MountDelegate; -import com.facebook.rendercore.MountDelegate.MountDelegateInput; import com.facebook.rendercore.RenderTreeNode; import com.facebook.rendercore.RenderUnit; import com.facebook.rendercore.extensions.MountExtension; +import com.facebook.rendercore.incrementalmount.IncrementalMountExtensionInput; import java.util.HashSet; import java.util.List; import java.util.Set; /** Extension for performing incremental mount. */ -public class IncrementalMountExtension - extends MountExtension { - - private static final Rect sTempRect = new Rect(); +public class IncrementalMountExtension extends MountExtension { private final Host mLithoView; - private int mPreviousTopsIndex; - private int mPreviousBottomsIndex; private final Rect mPreviousLocalVisibleRect = new Rect(); private final Set mComponentIdsMountedInThisFrame = new HashSet<>(); - private IncrementalMountExtensionInput mInput; - private final AttachDetachBinder mAttachDetachBinder = new AttachDetachBinder(); + private final IncrementalMountBinder mAttachDetachBinder = new IncrementalMountBinder(); private final LongSparseArray mPendingImmediateRemoval = new LongSparseArray<>(); - public RenderUnit.Binder getAttachDetachBinder() { - return mAttachDetachBinder; - } - - public interface IncrementalMountExtensionInput extends MountDelegateInput { - int getMountableOutputCount(); - - List getMountableOutputTops(); - - List getMountableOutputBottoms(); - - int getLayoutOutputPositionForId(long id); - } - - final class AttachDetachBinder implements RenderUnit.Binder { - - private boolean isUpdating = false; - - @Override - public boolean shouldUpdate( - LithoRenderUnit currentValue, - LithoRenderUnit newValue, - @Nullable Object currentLayoutData, - @Nullable Object nextLayoutData) { - isUpdating = true; - return true; - } - - @Override - public void bind( - Context context, - Object content, - LithoRenderUnit lithoRenderUnit, - @Nullable Object layoutData) { - if (!isUpdating) { - return; - } - - isUpdating = false; - - final LayoutOutput output = lithoRenderUnit.output; - final Component component = output.getComponent(); - - onItemUpdated(content, component); - } - - @Override - public void unbind( - Context context, Object o, LithoRenderUnit lithoRenderUnit, @Nullable Object layoutData) {} - } + private IncrementalMountExtensionInput mInput; + private int mPreviousTopsIndex; + private int mPreviousBottomsIndex; public IncrementalMountExtension(Host lithoView) { mLithoView = lithoView; @@ -161,14 +107,36 @@ public void onVisibleBoundsChanged(Rect localVisibleRect) { LithoStats.incrementComponentMountCount(); } - private void setVisibleRect(@Nullable Rect localVisibleRect) { - if (localVisibleRect != null) { - mPreviousLocalVisibleRect.set(localVisibleRect); + @Override + public void onUnbind() {} + + @Override + protected void acquireMountReference( + final RenderTreeNode renderTreeNode, + final int position, + final MountDelegate.MountDelegateInput input, + final boolean isMounting) { + // Make sure the host is mounted before the child. + final RenderTreeNode hostTreeNode = renderTreeNode.getParent(); + if (hostTreeNode != null) { + final long hostId = hostTreeNode.getRenderUnit().getId(); + if (!ownsReference(hostId)) { + final int hostIndex = mInput.getLayoutOutputPositionForId(hostId); + acquireMountReference(hostTreeNode, hostIndex, input, isMounting); + } } + + super.acquireMountReference(renderTreeNode, position, input, isMounting); } @Override - public void onUnbind() {} + public boolean canPreventMount() { + return true; + } + + public RenderUnit.Binder getAttachDetachBinder() { + return mAttachDetachBinder; + } private void releaseAcquiredReferencesForRemovedItems(IncrementalMountExtensionInput input) { if (mInput == null) { @@ -218,28 +186,9 @@ private void initIncrementalMount(Rect localVisibleRect, boolean isMounting) { setupPreviousMountableOutputData(localVisibleRect); } - @Override - protected void acquireMountReference( - RenderTreeNode renderTreeNode, - int position, - MountDelegate.MountDelegateInput input, - boolean isMounting) { - // Make sure the host is mounted before the child. - final RenderTreeNode hostTreeNode = renderTreeNode.getParent(); - if (hostTreeNode != null) { - final long hostId = hostTreeNode.getRenderUnit().getId(); - if (!ownsReference(hostId)) { - final int hostIndex = mInput.getLayoutOutputPositionForId(hostId); - acquireMountReference(hostTreeNode, hostIndex, input, isMounting); - } - } - - super.acquireMountReference(renderTreeNode, position, input, isMounting); - } - - private void onItemUpdated(Object content, Component component) { - if (component.hasChildLithoViews()) { - mountItemIncrementally(content, component); + private void setVisibleRect(@Nullable Rect localVisibleRect) { + if (localVisibleRect != null) { + mPreviousLocalVisibleRect.set(localVisibleRect); } } @@ -365,6 +314,22 @@ private void setupPreviousMountableOutputData(Rect localVisibleRect) { } } + @VisibleForTesting + int getPreviousTopsIndex() { + return mPreviousTopsIndex; + } + + @VisibleForTesting + int getPreviousBottomsIndex() { + return mPreviousBottomsIndex; + } + + static void onItemUpdated(Object content, Component component) { + if (component.hasChildLithoViews()) { + mountItemIncrementally(content, component); + } + } + private static boolean isMountedHostWithChildContent(@Nullable Object content) { if (!(content instanceof ComponentHost)) { return false; @@ -408,19 +373,4 @@ private static void mountViewIncrementally(View view, boolean mountingAll) { } } } - - @Override - public boolean canPreventMount() { - return true; - } - - @VisibleForTesting - int getPreviousTopsIndex() { - return mPreviousTopsIndex; - } - - @VisibleForTesting - int getPreviousBottomsIndex() { - return mPreviousBottomsIndex; - } } diff --git a/litho-core/src/main/java/com/facebook/litho/LayoutState.java b/litho-core/src/main/java/com/facebook/litho/LayoutState.java index 199a12f9c11..17c9944f260 100644 --- a/litho-core/src/main/java/com/facebook/litho/LayoutState.java +++ b/litho-core/src/main/java/com/facebook/litho/LayoutState.java @@ -57,13 +57,13 @@ import com.facebook.infer.annotation.ThreadSafe; import com.facebook.litho.ComponentTree.LayoutStateFuture; import com.facebook.litho.EndToEndTestingExtension.EndToEndTestingExtensionInput; -import com.facebook.litho.IncrementalMountExtension.IncrementalMountExtensionInput; import com.facebook.litho.annotations.ImportantForAccessibility; import com.facebook.litho.config.ComponentsConfiguration; import com.facebook.litho.drawable.BorderColorDrawable; import com.facebook.litho.stats.LithoStats; import com.facebook.rendercore.RenderTree; import com.facebook.rendercore.RenderTreeNode; +import com.facebook.rendercore.incrementalmount.IncrementalMountExtensionInput; import com.facebook.rendercore.visibility.VisibilityModuleInput; import com.facebook.rendercore.visibility.VisibilityOutput; import com.facebook.rendercore.visibility.VisibilityOutputsExtensionInput; diff --git a/litho-it/src/test/java/com/facebook/litho/IncrementalMountExtensionTest.java b/litho-it/src/test/java/com/facebook/litho/IncrementalMountExtensionTest.java index 7a7e714863b..39fd088f6ee 100644 --- a/litho-it/src/test/java/com/facebook/litho/IncrementalMountExtensionTest.java +++ b/litho-it/src/test/java/com/facebook/litho/IncrementalMountExtensionTest.java @@ -26,6 +26,7 @@ import com.facebook.rendercore.MountDelegate; import com.facebook.rendercore.RenderTreeNode; import com.facebook.rendercore.RenderUnit; +import com.facebook.rendercore.incrementalmount.IncrementalMountExtensionInput; import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -43,15 +44,13 @@ public void testDirtyMountWithEmptyRect() { extension.registerToDelegate(mountDelegate); - final IncrementalMountExtension.IncrementalMountExtensionInput incrementalMountExtensionInput = - new TestInput(10); + final IncrementalMountExtensionInput incrementalMountExtensionInput = new TestInput(10); extension.beforeMount(incrementalMountExtensionInput, new Rect(0, 0, 10, 50)); assertThat(extension.getPreviousBottomsIndex()).isEqualTo(0); assertThat(extension.getPreviousTopsIndex()).isEqualTo(5); - final IncrementalMountExtension.IncrementalMountExtensionInput incrementalMountExtensionInput2 = - new TestInput(3); + final IncrementalMountExtensionInput incrementalMountExtensionInput2 = new TestInput(3); extension.beforeMount(incrementalMountExtensionInput2, new Rect(0, 0, 0, 0)); // extension.onViewOffset(); @@ -71,15 +70,13 @@ public void testDirtyMountWithEmptyRect_leftRightMatch() { extension.registerToDelegate(mountDelegate); - final IncrementalMountExtension.IncrementalMountExtensionInput incrementalMountExtensionInput = - new TestInput(10); + final IncrementalMountExtensionInput incrementalMountExtensionInput = new TestInput(10); extension.beforeMount(incrementalMountExtensionInput, new Rect(0, 0, 10, 50)); assertThat(extension.getPreviousBottomsIndex()).isEqualTo(0); assertThat(extension.getPreviousTopsIndex()).isEqualTo(5); - final IncrementalMountExtension.IncrementalMountExtensionInput incrementalMountExtensionInput2 = - new TestInput(3); + final IncrementalMountExtensionInput incrementalMountExtensionInput2 = new TestInput(3); extension.beforeMount(incrementalMountExtensionInput2, new Rect(0, 0, 10, 0)); extension.onVisibleBoundsChanged(new Rect(0, 0, 10, 50)); @@ -88,7 +85,7 @@ public void testDirtyMountWithEmptyRect_leftRightMatch() { assertThat(extension.getPreviousTopsIndex()).isEqualTo(3); } - final class TestInput implements IncrementalMountExtension.IncrementalMountExtensionInput { + final class TestInput implements IncrementalMountExtensionInput { final List mountableOutputs = new ArrayList<>(); final List tops = new ArrayList<>(); final List bottoms = new ArrayList<>(); diff --git a/litho-rendercore-incremental-mount/src/main/java/com/facebook/rendercore/incrementalmount/IncrementalMountExtensionInput.java b/litho-rendercore-incremental-mount/src/main/java/com/facebook/rendercore/incrementalmount/IncrementalMountExtensionInput.java new file mode 100644 index 00000000000..30236da4481 --- /dev/null +++ b/litho-rendercore-incremental-mount/src/main/java/com/facebook/rendercore/incrementalmount/IncrementalMountExtensionInput.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.facebook.rendercore.incrementalmount; + +import com.facebook.rendercore.MountDelegate; +import com.facebook.rendercore.RenderTreeNode; +import java.util.List; + +public interface IncrementalMountExtensionInput extends MountDelegate.MountDelegateInput { + + int getMountableOutputCount(); + + List getMountableOutputTops(); + + List getMountableOutputBottoms(); + + int getLayoutOutputPositionForId(long id); +}