ReactNative 源码分析10——Native View创建流程createView

2 阅读4分钟

继续上一篇分析下面方法调用

  • createView
  • setChildren
  • manageChildren
  • onBatchComplete

讲完ReactShadowNode了我们可以看看createView,主要分3 步:

  • ①创建与JS侧对应的ReactShadowNode节点
  • ②updateProperties设置ReactShadowNode节点的属性
  • ③handleCreateView创建VIew
//UIImplementation.java
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
  synchronized (uiImplementationThreadLock) {
    //①
    ReactShadowNode cssNode = createShadowNode(className);
    ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
    Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist" );
    cssNode.setReactTag(tag); // Thread safety needed here
    cssNode.setViewClassName(className);
    cssNode.setRootTag(rootNode.getReactTag());
    cssNode.setThemedContext(rootNode.getThemedContext());

    mShadowNodeRegistry.addNode(cssNode);

    ReactStylesDiffMap styles = null;
    if (props != null) {
      styles = new ReactStylesDiffMap(props);
      //②
      cssNode.updateProperties(styles);
    }
    //③
    handleCreateView(cssNode, rootViewTag, styles);
  }
}

创建ShadowNode节点

第①点createShadowNode:

先看看createShadowNode

protected ReactShadowNode createShadowNode(String className) {
  ViewManager viewManager = mViewManagers.get(className);
  return viewManager.createShadowNodeInstance(mReactContext);
}

mViewManagers是ViewManagerRegistry

  • 先从缓存mViewManagers中查找
  • 如果没有调用getViewManagerFromResolver进行检索
public synchronized ViewManager get(String className) {
  // 1. Try to get the manager without the prefix.
  ViewManager viewManager = mViewManagers.get(className);
  if (viewManager != null) {
    return viewManager;
  }

  // 2. Try to get the manager with the RCT prefix.
  String rctViewManagerName = "RCT" + className;
  viewManager = mViewManagers.get(rctViewManagerName);
  if (viewManager != null) {
    return viewManager;
  }
  if (mViewManagerResolver != null) {
    // 1. Try to get the manager without the prefix.
    viewManager = getViewManagerFromResolver(className);
    if (viewManager != null) return viewManager;

    // 2. Try to get the manager with the RCT prefix.
    viewManager = getViewManagerFromResolver(rctViewManagerName);
    if (viewManager != null) return viewManager;
    ...
  }
}

getViewManagerFromResolver方法如下,重点是mViewManagerResolver是什么

private @Nullable ViewManager getViewManagerFromResolver(String className) {
  @Nullable ViewManager viewManager;
  viewManager = mViewManagerResolver.getViewManager(className);
  if (viewManager != null) {
    mViewManagers.put(className, viewManager);
  }
  return viewManager;
}

在《UIManagerModule构造函数》我们分析了mViewManagerResolver实际是

  ViewManagerResolver resolver =
      new ViewManagerResolver() {
        @Override
        public @Nullable ViewManager getViewManager(String viewManagerName) {
          return mReactInstanceManager.createViewManager(viewManagerName);
        }

        @Override
        public Collection<String> getViewManagerNames() {
          return mReactInstanceManager.getViewManagerNames();
        }
      };

也就是getViewManager最终调用的是mReactInstanceManager.createViewManager

public @Nullable ViewManager createViewManager(String viewManagerName) {
  ...
  synchronized (mPackages) {
    for (ReactPackage reactPackage : mPackages) {
      if (reactPackage instanceof ViewManagerOnDemandReactPackage) {
        ViewManager viewManager =
            ((ViewManagerOnDemandReactPackage) reactPackage)
                .createViewManager(context, viewManagerName);
        if (viewManager != null) {
          return viewManager;
        }
      }
    }
  }
  return null;
}

在createViewManager中会根据viewManagerName查找到对应的ViewManager,以RCTRawText为例

RN组件classNameShadowNodeViewViewManager
TextRCTTextReactTextShadowNodeReactTextViewReactTextViewManager
ViewRCTViewLayoutShadowNodeReactViewGroupReactViewManager
@VisibleForTesting public static final String REACT_CLASS = "RCTText" ;

@ReactModule(name = ReactTextViewManager.REACT_CLASS)
public class ReactTextViewManager
    extends ReactTextAnchorViewManager<ReactTextView, ReactTextShadowNode>
    implements IViewManagerWithChildren 

所以在这个案例中mViewManagers.get(className)返回的是ReactTextViewManager,继续看看createShadowNodeInstance

@Override
public ReactTextShadowNode createShadowNodeInstance() {
  return new ReactTextShadowNode(mReactTextViewManagerCallback);
}

ReactTextShadowNode是ReactShadowNodeImpl的子类,这就是在上一篇《ReactShadowNode》中分析,JS中的节点会映射到ReactTextShadowNode,然后形成 4 棵树。

设置属性

第②点updateProperties:

public static <T extends ReactShadowNode> void updateProps(T node, ReactStylesDiffMap props) {
  ShadowNodeSetter<T> setter = findNodeSetter(node.getClass());
  Iterator<Map.Entry<String, Object>> iterator = props.mBackingMap.getEntryIterator();
  while (iterator.hasNext()) {
    Map.Entry<String, Object> entry = iterator.next();
    setter.setProperty(node, entry.getKey(), entry.getValue());
  }
}

调用findNodeSetter查找ShadowNodeSetter

  • SHADOW_NODE_SETTER_MAP缓存加速作用
  • 调用findGeneratedSetter获取ShadowNodeSetter
  • 如果没找到使用默认的FallbackShadowNodeSetter
private static <T extends ReactShadowNode> ShadowNodeSetter<T> findNodeSetter(
    Class<? extends ReactShadowNode> nodeClass) {
  @SuppressWarnings( "unchecked" )
  ShadowNodeSetter<T> setter = (ShadowNodeSetter<T>) SHADOW_NODE_SETTER_MAP.get(nodeClass);
  if (setter == null) {
    setter = findGeneratedSetter(nodeClass);
    if (setter == null) {
      setter = new FallbackShadowNodeSetter<>(nodeClass);
    }
    SHADOW_NODE_SETTER_MAP.put(nodeClass, setter);
  }

  return setter;
}

findGeneratedSetter通过反射查找名字为 "RCTText$$PropsSetter" 的类(以前面RCTText为例)

private static <T> T findGeneratedSetter(Class<?> cls) {
  String clsName = cls.getName();
  try {
    Class<?> setterClass = Class.forName(clsName + "$$PropsSetter" );
    //noinspection unchecked
    return (T) setterClass.newInstance();
  } catch (ClassNotFoundException e) {
    FLog.w(TAG, "Could not find generated setter for " + cls);
    return null;
  } catch (InstantiationException | IllegalAccessException e) {
    throw new RuntimeException( "Unable to instantiate methods getter for " + clsName, e);
  }
}

那 **"RCTTextPropsSetter"生成类从哪来:注解处理器ReactPropertyProcessor.java扫描@ReactPropertyHolder,为每个ViewManager/ShadowNode生成XXXPropsSetter"** 生成类从哪来:注解处理器`ReactPropertyProcessor`.java 扫描 `@ReactPropertyHolder`,为每个 ViewManager / ShadowNode 生成 `XXXPropsSetter,并实现 ShadowNodeSetter,内部是 switch(name)直接调node.xxx(...),避免反射比稿效率。ReactTextViewManager是继承ViewManager,而ViewManager用注解@ReactPropertyHolder`修饰的

@ReactModule(name = ReactTextViewManager.REACT_CLASS)
public class ReactTextViewManager
    extends ReactTextAnchorViewManager<ReactTextView, ReactTextShadowNode>
    implements IViewManagerWithChildren
    
@ReactPropertyHolder
public abstract class ViewManager<T extends View, C extends ReactShadowNode>
    extends BaseJavaModule

"RCTText$$PropsSetter" 类中实现了ShadowNodeSetter接口,其实现的内部是 switch(name) 直接调 ReactShadowNode.xxx(...)

public interface ShadowNodeSetter<T extends ReactShadowNode> extends Settable {
  void setProperty(T node, String name, Object value);
}

那么这个switch(name)是如何构建实现的呢?它是注解处理器解析ViewManager中的@ReactProp属性实现的

@ReactModule(name = ReactTextViewManager.REACT_CLASS)
public class ReactTextViewManager
    extends ReactTextAnchorViewManager<ReactTextView, ReactTextShadowNode>
    implements IViewManagerWithChildren {
    
    @ReactProp(name = "overflow" )
    public void setOverflow(ReactTextView view, @Nullable String overflow) {
      view.setOverflow(overflow);
    }
}

//父类
@ReactModule(name = ReactTextViewManager.REACT_CLASS)
public class ReactTextViewManager
    extends ReactTextAnchorViewManager<ReactTextView, ReactTextShadowNode>
    implements IViewManagerWithChildren {
    @ReactProp(name = ViewProps.ADJUSTS_FONT_SIZE_TO_FIT)
    public void setAdjustFontSizeToFit(ReactTextView view, boolean adjustsFontSizeToFit) {
      view.setAdjustFontSizeToFit(adjustsFontSizeToFit);
    }
    
    @ReactProp(name = ViewProps.FONT_SIZE)
    public void setFontSize(ReactTextView view, float fontSize) {
      view.setFontSize(fontSize);
    }
}
  • 当JS中设置了overflow属性——>RCTText$$PropsSetter.setProperty——>ReactTextShadowNode.setOverflow
  • ReactTextShadowNode.setOverflow是在父类LayoutShadowNode中实现的
@ReactProp(name = ViewProps.OVERFLOW)
public void setOverflow(@Nullable String overflow)

创建Native View

第③点handleCreateView:

protected void handleCreateView(
    ReactShadowNode cssNode, int rootViewTag, @Nullable ReactStylesDiffMap styles) {
  if (!cssNode.isVirtual()) {
    mNativeViewHierarchyOptimizer.handleCreateView(cssNode, cssNode.getThemedContext(), styles);
  }
}

逻辑:只对非虚拟节点执行。虚拟节点(如嵌套文本 <Text> 内的 <Text>)不映射到原生 View,直接跳过。

public boolean isVirtual() { return false; }

默认返回 false。只有 ReactTextShadowNodeReactRawTextShadowNode 等子类会覆盖为 true。虚拟节点:

  • 不创建 YogaNode(mYogaNode = null
  • 不参与 Yoga 布局计算
  • 不映射到任何原生 View

视图层级优化器:NativeViewHierarchyOptimizer#handleCreateView

  • 判断节点是否是纯布局节点,如果是虚拟节点或纯布局节点,无原生 View

  • 三种 NativeKind

    • NONE — 虚拟节点或纯布局节点,无原生 View
    • LEAF — 无子节点,需要原生 View
    • PARENT — 有子节点,需要原生 ViewGroup
public void handleCreateView(
    ReactShadowNode node,
    ThemedReactContext themedContext,
    @Nullable ReactStylesDiffMap initialProps) {
  ....
  boolean isLayoutOnly =
      node.getViewClass().equals(ViewProps.VIEW_CLASS_NAME)
          && isLayoutOnlyAndCollapsable(initialProps);
  node.setIsLayoutOnly(isLayoutOnly);

  if (node.getNativeKind() != NativeKind.NONE) {
    mUIViewOperationQueue.enqueueCreateView(
        themedContext, node.getReactTag(), node.getViewClass(), initialProps);
  }
}

向mNonBatchedOperations队列中添加了一个CreateViewOperation

public void enqueueCreateView(
    ThemedReactContext themedContext,
    int viewReactTag,
    String viewClassName,
    @Nullable ReactStylesDiffMap initialProps) {
  synchronized (mNonBatchedOperationsLock) {
    mCreateViewCount++;
    mNonBatchedOperations.addLast(
        new CreateViewOperation(themedContext, viewReactTag, viewClassName, initialProps));
  }
}

mNonBatchedOperations队列在某个时机会被统一调度,这个调度时机后面会进行分析,我们继续看CreateViewOperation,它调用mNativeViewHierarchyManager.createView

public synchronized void createView(
    ThemedReactContext themedContext,
    int tag,
    String className,
    @Nullable ReactStylesDiffMap initialProps) {
  try {
    ViewManager viewManager = mViewManagers.get(className);

    View view =
        viewManager.createView(tag, themedContext, initialProps, null, mJSResponderHandler);
    mTagsToViews.put(tag, view);
    mTagsToViewManagers.put(tag, viewManager);
  } finally {
    Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
  }
}

调用createView中会调用createViewInstance创建Native VIew

protected @NonNull T createViewInstance(
    int reactTag,
    @NonNull ThemedReactContext reactContext,
    @Nullable ReactStylesDiffMap initialProps,
    @Nullable StateWrapper stateWrapper) {
  T view = null;
  @Nullable Stack<T> recyclableViews = getRecyclableViewStack(reactContext.getSurfaceId(), true);
  if (recyclableViews != null && !recyclableViews.empty()) {
    view = recycleView(reactContext, recyclableViews.pop());
  } else {
    //创建View
    view = createViewInstance(reactContext);
  }
  //设置id
  view.setId(reactTag);
  ...
  return view;
}

createViewInstance是一个抽象方法,每一个实现ViewManager接口的类都必须实现这个方法

protected abstract @NonNull T createViewInstance(@NonNull ThemedReactContext reactContext);

对于ReactTextViewManager的实现如下,这里返回了真正的Native View

@Override
public ReactTextView createViewInstance(ThemedReactContext context) {
  return new ReactTextView(context);
}

最后将tag与view、viewManager关系使用mTagsToViews和mTagsToViewManagers记录下来。