ReactNative 源码分析11——Native View创建流程setChildren和manageChildren

本篇文章继续分析setChildren方法

  • setChildren
  • manageChildren
  • onBatchComplete

setChildren

JS 端 finalizeInitialChildren 发送 UIManager.setChildren(parentTag, [childTag1, childTag2, ...])。它是 manageChildren 的简化版,只在首次挂载时使用,假设子节点按顺序排列。

与 manageChildren 的对比:

setChildren manageChildren
调用时机 首次挂载 后续增删移动
支持操作 仅添加 添加 + 移动 + 删除
子节点顺序 按数组顺序 需要指定 index
性能 更快(无需排序) 需要排序和校验
ini 复制代码
public void setChildren(int viewTag, ReadableArray childrenTags) {
  synchronized (uiImplementationThreadLock) {
    ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);

    for (int i = 0; i < childrenTags.size(); i++) {
      ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(childrenTags.getInt(i));
      if (cssNodeToAdd == null) {
        throw new IllegalViewOperationException(
            "Trying to add unknown view tag: " + childrenTags.getInt(i));
      }
      cssNodeToManage.addChildAt(cssNodeToAdd, i);
    }

    mNativeViewHierarchyOptimizer.handleSetChildren(cssNodeToManage, childrenTags);
  }
}
  • cssNodeToManage标识查找到的父节点
  • cssNodeToManage.addChildAt建立父子节点关系
objectivec 复制代码
xiao1:ReactNative       (UIManager.createView) tag: 3, class: RCTRawText, props: {"text":"App.tsx"}
xiao1:ReactNative       (UIManager.createView) tag: 5, class: RCTText, props: {"margin":10,"allowFontScaling":true,"textAlign":"center","ellipsizeMode":"tail","fontSize":20,"accessible":false}
xiao1:ReactNative       (UIManager.setChildren) tag: 5, children: [3]

当上面的日志执行完后就会构建出ShadowNode、YogaNode、YGNode节点树:

scss 复制代码
ShadowNode 树(JS 语义)              Yoga 树(布局计算)
┌──────────────┐        ┌──────────────┐
│ View(tag=5)  │                  │ YogaNode(5)  │
│  mChildren:  │                  │  children:   │
│   [3]    │                      │   [yn3]│
└──────────────┘         └──────────────┘
         │                                    │
  ┌───┴───┐                       ┌───┴───┐
  ▼            ▼                       ▼           ▼
Text(3)                                YN(3)   

继续看handleSetChildren,这个循环对每个子节点调用 addNodeToNode

ini 复制代码
public void handleSetChildren(ReactShadowNode nodeToManage, ReadableArray childrenTags) {
  for (int i = 0; i < childrenTags.size(); i++) {
    ReactShadowNode nodeToAdd = mShadowNodeRegistry.getNode(childrenTags.getInt(i));
    addNodeToNode(nodeToManage, nodeToAdd, i);
  }
}

addNodeToNode中逻辑比较复杂,但是它最终会调用如下代码

csharp 复制代码
mUIViewOperationQueue.enqueueManageChildren(
    parent.getReactTag(),
    null,
    new ViewAtIndex[] {new ViewAtIndex(child.getReactTag(), index)},
    null);
  • enqueueManageChildren里面是向mOperations队列添加了一个ManageChildrenOperation
  • 看到这里是不是有点熟悉,在讲setChildren时它最终是向mNonBatchedOperations队列中添加了一个CreateViewOperation

ManageChildrenOperation最终调用mNativeViewHierarchyManager.manageChildren,manageChildren核心作用:负责Native View视图的增删管理

  • 当viewsToAdd不为空时最终是会调用viewManager.addView,本质与常用的addView完全一致
less 复制代码
public synchronized void manageChildren(
    final int tag,
    @Nullable int[] indicesToRemove,
    @Nullable ViewAtIndex[] viewsToAdd,
    @Nullable int[] tagsToDelete) {
  ...
  if (viewsToAdd != null) {
    for (int i = 0; i < viewsToAdd.length; i++) {
      ViewAtIndex viewAtIndex = viewsToAdd[i];
      View viewToAdd = mTagsToViews.get(viewAtIndex.mTag);

      int normalizedIndex = viewAtIndex.mIndex;
      if (!pendingDeletionTags.isEmpty()) {
        normalizedIndex = 0;
        int counter = 0;
        while (normalizedIndex < viewToManage.getChildCount()) {
          if (counter == viewAtIndex.mIndex) {
            break;
          }
          View v = viewToManage.getChildAt(normalizedIndex);
          if (!pendingDeletionTags.contains(v.getId())) {
            counter++;
          }
          normalizedIndex++;
        }
      }
      //添加视图
      viewManager.addView(viewToManage, viewToAdd, normalizedIndex);
    }
  }
}

最后总结一下setChildren:它负责关联ShadowNode、YogaNode、YGNode、Native View之间的父子关系,最后形成如下图所示的 4 颗树

【图片原文】

manageChildren

它负责JS视频的增删改,和setChildren分为 2 个核心的:

  • ①部分负责更新ShadowNode、YogaNode、YGNode节点树
  • ②部分负责更新Native View节点树
less 复制代码
public void manageChildren(
    int viewTag,
    @Nullable ReadableArray moveFrom,
    @Nullable ReadableArray moveTo,
    @Nullable ReadableArray addChildTags,
    @Nullable ReadableArray addAtIndices,
    @Nullable ReadableArray removeFrom) {
    //①  
    for (int i = 0; i < viewsToAdd.length; i++) {
      ViewAtIndex viewAtIndex = viewsToAdd[i];
      ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag);
      if (cssNodeToAdd == null) {
        throw new IllegalViewOperationException(
            "Trying to add unknown view tag: " + viewAtIndex.mTag);
      }
      cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
    }
    //②
    mNativeViewHierarchyOptimizer.handleManageChildren(
        cssNodeToManage, indicesToRemove, tagsToRemove, viewsToAdd, tagsToDelete);

    for (int i = 0; i < tagsToDelete.length; i++) {
      removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
    }
  }
}

handleManageChildren中针对每个子节点也是调用addNodeToNode,最后还是向mOperations队列添加了一个ManageChildrenOperation。

相关推荐
aqi009 小时前
鸿蒙版本的电子书阅读APP开放源码啦
android·华为·ai编程·harmonyos·鸿蒙
墨天梦10 小时前
B19_SunnyWeather到阅读客户端
android·kotlin
美狐美颜sdk11 小时前
直播APP源码可以直接接入视频美颜sdk吗?技术方案详解
android·人工智能·音视频·美颜sdk·直播美颜sdk
用户693717500138413 小时前
2026,程序员的时代拐点到了
android·前端·后端
浪潮IT馆15 小时前
Android Studio 非最新版本下载安装教程
android·ide·android studio
xiaozongt198916 小时前
MasterGo + Claude Code 生成 Android 布局:完整实践指南
android
Anhty17 小时前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_9159090619 小时前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
狗凯之家源码网20 小时前
AI 步数修改提交系统源码应用场景与落地指南
android·数据库·人工智能·运动步数
ZHOUPUYU20 小时前
PHP 9.0 前瞻:下一代 PHP 会带来哪些新功能?
android·开发语言·php