/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.widget; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import android.support.v4.util.Pools; import com.facebook.litho.Component; import com.facebook.litho.ComponentContext; import com.facebook.litho.ComponentInfo; import com.facebook.litho.ComponentTree; import com.facebook.litho.LayoutHandler; import com.facebook.litho.Size; import com.facebook.litho.StateHandler; /** * A class used to store the data backing a {@link RecyclerBinder}. For each item the * ComponentTreeHolder keeps the {@link ComponentInfo} which contains the original {@link Component} * and either the {@link ComponentTree} or the {@link StateHandler} depending upon whether * the item is within the current working range or not. */ @ThreadSafe public class ComponentTreeHolder { private static final Pools.SynchronizedPool<ComponentTreeHolder> sComponentTreeHoldersPool = new Pools.SynchronizedPool<>(8); @GuardedBy("this") private ComponentTree mComponentTree; @GuardedBy("this") private StateHandler mStateHandler; @GuardedBy("this") private ComponentInfo mComponentInfo; private boolean mIsTreeValid; private LayoutHandler mLayoutHandler; private boolean mCanPrefetchDisplayLists; static ComponentTreeHolder acquire( ComponentInfo componentInfo, LayoutHandler layoutHandler, boolean canPrefetchDisplayLists) { ComponentTreeHolder componentTreeHolder = sComponentTreeHoldersPool.acquire(); if (componentTreeHolder == null) { componentTreeHolder = new ComponentTreeHolder(); } componentTreeHolder.mComponentInfo = componentInfo; componentTreeHolder.mLayoutHandler = layoutHandler; componentTreeHolder.mCanPrefetchDisplayLists = canPrefetchDisplayLists; return componentTreeHolder; } synchronized void acquireStateHandlerAndReleaseTree() { acquireStateHandler(); releaseTree(); } synchronized void invalidateTree() { mIsTreeValid = false; } synchronized void clearStateHandler() { mStateHandler = null; } void computeLayoutSync( ComponentContext context, int widthSpec, int heightSpec, Size size) { final ComponentTree componentTree; final Component component; synchronized (this) { ensureComponentTree(context); componentTree = mComponentTree; component = mComponentInfo.getComponent(); } componentTree.setRootAndSizeSpec(component, widthSpec, heightSpec, size); synchronized (this) { if (componentTree == mComponentTree && component == mComponentInfo.getComponent()) { mIsTreeValid = true; } } } void computeLayoutAsync( ComponentContext context, int widthSpec, int heightSpec) { final ComponentTree componentTree; final Component component; synchronized (this) { ensureComponentTree(context); componentTree = mComponentTree; component = mComponentInfo.getComponent(); } componentTree.setRootAndSizeSpecAsync(component, widthSpec, heightSpec); synchronized (this) { if (mComponentTree == componentTree && component == mComponentInfo.getComponent()) { mIsTreeValid = true; } } } synchronized ComponentInfo getComponentInfo() { return mComponentInfo; } synchronized boolean isTreeValid() { return mIsTreeValid; } synchronized ComponentTree getComponentTree() { return mComponentTree; } synchronized void setComponentInfo(ComponentInfo componentInfo) { invalidateTree(); mComponentInfo = componentInfo; } synchronized void release() { releaseTree(); clearStateHandler(); mComponentInfo = null; mLayoutHandler = null; mCanPrefetchDisplayLists = false; sComponentTreeHoldersPool.release(this); } @GuardedBy("this") private void ensureComponentTree(ComponentContext context) { if (mComponentTree == null) { mComponentTree = ComponentTree.create(context, mComponentInfo.getComponent()) .layoutThreadHandler(mLayoutHandler) .stateHandler(mStateHandler) .canPrefetchDisplayLists(mCanPrefetchDisplayLists) .build(); } } @GuardedBy("this") private void releaseTree() { if (mComponentTree != null) { mComponentTree.release(); mComponentTree = null; } mIsTreeValid = false; } @GuardedBy("this") private void acquireStateHandler() { if (mComponentTree == null) { return; } mStateHandler = mComponentTree.getStateHandler(); } }