public void measure()

in litho-widget/src/main/java/com/facebook/litho/widget/RecyclerBinder.java [2242:2369]


  public void measure(
      Size outSize,
      int widthSpec,
      int heightSpec,
      @Nullable EventHandler<ReMeasureEvent> reMeasureEventHandler) {
    // This is a hack to try to give a signal to applyReadyBatches whether it should even attempt
    // to acquire the lock or bail and let measure schedule it as a runnable. This can go away
    // once we break up the locking in measure.
    // TODO(t37195892): Do not hold lock throughout measure call in RecyclerBinder
    final boolean canRemeasure = reMeasureEventHandler != null;
    final int scrollDirection = mLayoutInfo.getScrollDirection();

    validateMeasureSpecs(widthSpec, heightSpec, canRemeasure, scrollDirection);

    final boolean shouldMeasureItemForSize =
        shouldMeasureItemForSize(widthSpec, heightSpec, scrollDirection, canRemeasure);
    if (mHasManualEstimatedViewportCount && shouldMeasureItemForSize) {
      throw new RuntimeException(
          "Cannot use manual estimated viewport count when the RecyclerBinder needs an item to determine its size!");
    }

    mIsInMeasure.set(true);

    try {
      synchronized (this) {
        if (mLastWidthSpec != LayoutManagerOverrideParams.UNINITIALIZED
            && !mRequiresRemeasure.get()
            && !mWrapContent) {
          switch (scrollDirection) {
            case VERTICAL:
              if (mMeasuredSize != null
                  && MeasureComparisonUtils.isMeasureSpecCompatible(
                      mLastWidthSpec, widthSpec, mMeasuredSize.width)) {
                outSize.width = mMeasuredSize.width;
                outSize.height = mWrapContent ? mMeasuredSize.height : SizeSpec.getSize(heightSpec);

                return;
              }
              break;
            default:
              if (mMeasuredSize != null
                  && MeasureComparisonUtils.isMeasureSpecCompatible(
                      mLastHeightSpec, heightSpec, mMeasuredSize.height)) {
                outSize.width = mWrapContent ? mMeasuredSize.width : SizeSpec.getSize(widthSpec);
                outSize.height = mMeasuredSize.height;

                return;
              }
          }

          mIsMeasured.set(false);
          invalidateLayoutData();
        }

        // We have never measured before or the measures are not valid so we need to measure now.
        mLastWidthSpec = widthSpec;
        mLastHeightSpec = heightSpec;

        if (!hasComputedRange()) {
          final ComponentTreeHolderRangeInfo holderForRangeInfo = getHolderForRangeInfo();
          if (holderForRangeInfo != null) {
            initRange(
                SizeSpec.getSize(widthSpec),
                SizeSpec.getSize(heightSpec),
                holderForRangeInfo,
                scrollDirection);
          }
        }

        final Size initialMeasuredSize =
            getInitialMeasuredSize(widthSpec, heightSpec, canRemeasure);

        // At this point we might still not have a range. In this situation we should return the
        // best size we can detect from the size spec and update it when the first item comes in.
        switch (scrollDirection) {
          case OrientationHelper.VERTICAL:
            if (!shouldMeasureItemForSize || mSizeForMeasure != null) {
              mReMeasureEventEventHandler = mWrapContent ? reMeasureEventHandler : null;
            } else {
              mReMeasureEventEventHandler = reMeasureEventHandler;
              mRequiresRemeasure.set(!mWrapContent);
            }
            break;

          case OrientationHelper.HORIZONTAL:
          default:
            if (!shouldMeasureItemForSize || mSizeForMeasure != null) {
              mReMeasureEventEventHandler =
                  (mHasDynamicItemHeight || mWrapContent) ? reMeasureEventHandler : null;
              mRequiresRemeasure.set(mHasDynamicItemHeight);
            } else {
              mReMeasureEventEventHandler = reMeasureEventHandler;
              mRequiresRemeasure.set(!mWrapContent);
            }
            break;
        }

        if (mWrapContent) {
          final Size wrapSize = new Size();
          fillListViewport(initialMeasuredSize.width, initialMeasuredSize.height, wrapSize);
          outSize.width = wrapSize.width;
          outSize.height = wrapSize.height;
        } else {
          outSize.width = initialMeasuredSize.width;
          outSize.height = initialMeasuredSize.height;
        }

        mMeasuredSize = new Size(outSize.width, outSize.height);
        mIsMeasured.set(true);

        if (mComponentWarmer != null) {
          mComponentWarmer.setComponentTreeHolderFactory(getComponentTreeHolderPreparer());
        }

        maybeFillHScrollViewport();
        updateAsyncInsertOperations();

        if (mEstimatedViewportCount != RecyclerView.NO_POSITION) {
          computeRange(mCurrentFirstVisiblePosition, mCurrentLastVisiblePosition);
        }
      }
    } finally {
      mIsInMeasure.set(false);
      if (mHasAsyncOperations) {
        ensureApplyReadyBatches();
      }
    }
  }