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

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

  • createView
  • setChildren
  • manageChildren
  • onBatchComplete

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

  • ①创建与JS侧对应的ReactShadowNode节点
  • ②updateProperties设置ReactShadowNode节点的属性
  • ③handleCreateView创建VIew
scss 复制代码
//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

typescript 复制代码
protected ReactShadowNode createShadowNode(String className) {
  ViewManager viewManager = mViewManagers.get(className);
  return viewManager.createShadowNodeInstance(mReactContext);
}

mViewManagers是ViewManagerRegistry

  • 先从缓存mViewManagers中查找
  • 如果没有调用getViewManagerFromResolver进行检索
kotlin 复制代码
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是什么

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

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

typescript 复制代码
  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

java 复制代码
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组件 className ShadowNode View ViewManager
Text RCTText ReactTextShadowNode ReactTextView ReactTextViewManager
View RCTView LayoutShadowNode ReactViewGroup ReactViewManager
java 复制代码
@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

typescript 复制代码
@Override
public ReactTextShadowNode createShadowNodeInstance() {
  return new ReactTextShadowNode(mReactTextViewManagerCallback);
}

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

设置属性

第②点updateProperties:

typescript 复制代码
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
ini 复制代码
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为例)

typescript 复制代码
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);
  }
}

那 **"RCTText <math xmlns="http://www.w3.org/1998/Math/MathML"> P r o p s S e t t e r " ∗ ∗ 生成类从哪来:注解处理器 ' R e a c t P r o p e r t y P r o c e s s o r ' . j a v a 扫描 ' @ R e a c t P r o p e r t y H o l d e r ' ,为每个 V i e w M a n a g e r / S h a d o w N o d e 生成 ' X X X PropsSetter"** 生成类从哪来:注解处理器`ReactPropertyProcessor`.java 扫描 `@ReactPropertyHolder`,为每个 ViewManager / ShadowNode 生成 `XXX </math>PropsSetter"∗∗生成类从哪来:注解处理器'ReactPropertyProcessor'.java扫描'@ReactPropertyHolder',为每个ViewManager/ShadowNode生成'XXXPropsSetter,并实现 ShadowNodeSetter,内部是 switch(name)直接调node.xxx(...),避免反射比稿效率。ReactTextViewManager是继承ViewManager,而ViewManager用注解@ReactPropertyHolder`修饰的

scala 复制代码
@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(...)

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

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

java 复制代码
@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中实现的
less 复制代码
@ReactProp(name = ViewProps.OVERFLOW)
public void setOverflow(@Nullable String overflow)

创建Native View

第③点handleCreateView:

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

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

typescript 复制代码
public boolean isVirtual() { return false; }

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

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

视图层级优化器:NativeViewHierarchyOptimizer#handleCreateView

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

  • 三种 NativeKind

    • NONE --- 虚拟节点或纯布局节点,无原生 View
    • LEAF --- 无子节点,需要原生 View
    • PARENT --- 有子节点,需要原生 ViewGroup
less 复制代码
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

less 复制代码
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

java 复制代码
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

less 复制代码
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接口的类都必须实现这个方法

less 复制代码
protected abstract @NonNull T createViewInstance(@NonNull ThemedReactContext reactContext);

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

typescript 复制代码
@Override
public ReactTextView createViewInstance(ThemedReactContext context) {
  return new ReactTextView(context);
}

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

相关推荐
用户86022504674722 小时前
从入门到进阶的 React Native 实战指南
android·前端
问心无愧05132 小时前
ctf show web入门98
android·前端·笔记
李斯维2 小时前
Jetpack 生命周期组件 Lifecycle 的设计思想和使用
android·android studio·android jetpack
Mr YiRan2 小时前
Android构建优化:基于Git Diff+TaskGraph
android·git·elasticsearch
赏金术士2 小时前
第二章:Compose入门—声明式UI编程
android·ui·kotlin·compose
星间都市山脉2 小时前
Android 谷歌 VTS 完整测试
android
坏小虎2 小时前
【聊天列表组件选型建议】FlashList、FlatList、LegendList三种列表组件
javascript·react native·react.js
齊家治國平天下3 小时前
Android 14 AIDL HAL 使用指南-获取服务流程解析
android·hal·aidl·servicemanager·aidl hal·获取服务
张二娃同学3 小时前
02_C语言数据类型_整型浮点型字符型一次讲清楚
android·java·c语言