ReactNative源码分析之UIViewOperationQueue

本文深入分析ReactNative 0.61.5版本的UIViewOperationQueue,探讨UIOperation和ViewOperation如何工作,以及dispatchViewUpdates的触发与执行时机。在UIManagerModule完成JS批处理后,UIViewOperationQueue缓存的UI命令批量执行,确保UI一致性。通过dispatchPendingNonBatchedOperations和flushPendingBatches处理nonBatchedOperations和batchedOperations,所有操作最终由NativeViewHierarchyManager代理执行。
摘要由CSDN通过智能技术生成

当前分析的ReactNative版本为0.61.5:

看这边文章之前最好先了解UIManagerModule和UIImplementation:
1.ReactNative源码分析之UIManagerModule.
2.ReactNative源码分析之UIImplementation.

从UIViewOperationQueue名称可知,首先该类是一个操作UIView为主,同时具有缓存功能的这样一个类。

看下这个类的定义:

/**
 * This class acts as a buffer for command executed on {@link NativeViewHierarchyManager}. It expose
 * similar methods as mentioned classes but instead of executing commands immediately it enqueues
 * those operations in a queue that is then flushed from {@link UIManagerModule} once JS batch of ui
 * operations is finished. This is to make sure that we execute all the JS operation coming from a
 * single batch a single loop of the main (UI) android looper.
 *
 * <p>TODO(7135923): Pooling of operation objects TODO(5694019): Consider a better data structure
 * for operations queue to save on allocations
 */
public class UIViewOperationQueue {
   
}

该类扮演buffer的角色,接收command命令,这些命令会在NativeViewHierarchyManager中执行。

这些command并不会立即执行,它首先会进入缓存队列,所有command会在UIManagerModule执行完JS batch后再执行。保证了一批js命令执行后,缓存中的UI command也能一次性执行完。

一、UIOperation和ViewOperation

ViewOperation实现UIOperation接口,既然是对相关View的操作,需要传入相关View的tag。

举例看下具体实现:

  private final class RemoveRootViewOperation extends ViewOperation {
   

    public RemoveRootViewOperation(int tag) {
   
      super(tag);
    }

    @Override
    public void execute() {
   
      mNativeViewHierarchyManager.removeRootView(mTag);
    }
  }

这个是删除RootView的UI操作,本质上是由NativeViewHierarchyManager代理执行。

再来看看UpdatePropertiesOperation定义:

  private final class UpdatePropertiesOperation extends ViewOperation {
   

    private final ReactStylesDiffMap mProps;

    private UpdatePropertiesOperation(int tag, ReactStylesDiffMap props) {
   
      super(tag);
      mProps = props;
    }

    @Override
    public void execute() {
   
      mNativeViewHierarchyManager.updateProperties(mTag, mProps);
    }
  }

也是类似,真正是由NativeViewHierarchyManager代理执行。

定义的UIViewOperation都有哪些呢?如下:
1.ChangeJSResponderOperation;
2.ConfigureLayoutAnimationOperation;
3.CreateViewOperation;
4.DismissPopupMenuOperation;
5.DispatchStringCommandOperation;
6.FindTargetForTouchOperation;
7.LayoutUpdateFinishedOperation;
8.ManageChildrenOperation;
9.MeasureOperation;
10.MeasureInWindowOperation;
11.EmitOnLayoutEventOperation;
12.RemoveRootViewOperation;
13.SendAccessibilityEvent;
14.SetChildrenOperation;
15.SetLayoutAnimationEnabledOperation;
16.ShowPopupMenuOperation;
17.UIBlockOperation;
18.UpdateViewExtraData;
19.UpdateInstanceHandleOperation;
20.UpdateLayoutOperation;
21.UpdatePropertiesOperation;

所有的都是对UI的操作,最终是由NativeViewHierarchyManager执行。

二、dispatchViewUpdates

如上分析可知,所有的UI操作都会进入到缓存队列,那么什么时候批量执行呢?

dispatchViewUpdates会在onBatchComplete方法进行触发,onBatchComplete方法后续会进行分析。

看该方法之前,先来看看DispatchUIFrameCallback定义:

/**
   * Choreographer FrameCallback responsible for actually dispatching view updates on the UI thread
   * that were enqueued via {@link #dispatchViewUpdates(int)}. The reason we don't just enqueue
   * directly to the UI thread from that method is to make sure our Runnables actually run before
   * the next traversals happen:
   *
   * <p>ViewRootImpl#scheduleTraversals (which is called from invalidate, requestLayout, etc) calls
   * Looper#postSyncBarrier which keeps any UI thread looper messages from being processed until
   * that barrier is removed during the next traversal. That means, depending on when we get updates
   * from JS and what else is happening on the UI thread, we can sometimes try to post this runnable
   * after ViewRootImpl has posted a barrier.
   *
   * <p>Using a Choreographer callback (which runs immediately before traversals), we guarantee we
   * run before the next traversal.
   */
  private class DispatchUIFrameCallback extends GuardedFrameCallback {
   

    private static final int FRAME_TIME_MS = 16;
    private final int mMinTimeLeftInFrameForNonBatchedOperationMs;

    private DispatchUIFrameCallback(
        ReactContext reactContext, int minTimeLeftInFrameForNonBatchedOperationMs) {
   
      super(reactContext);
      mMinTimeLeftInFrameForNonBatchedOperationMs = minTimeLeftInFrameForNonBatchedOperationMs;
    }

    @Override
    public void doFrameGuarded(long frameTimeNanos) {
   
      if (mIsInIllegalUIState) {
   
        FLog.w(
            ReactConstants.TAG,
            "Not flushing pending UI operations because of previously thrown Exception");
        return;
      }

      Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "dispatchNonBatchedUIOperations");
      try {
   
        dispatchPendingNonBatchedOperations(frameTimeNanos);
      } finally {
   
        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值