Weex源码分析之Dom构建&Render

流程

WXBridge.callNative-->WXDomManager.executeAction-->DomAction.executeDom-->DomAction.executeRender

渲染实例

WXBridge.callNative(JSThread)

tasks:[{"module":"dom","method":"createBody","args":[{"ref":"_root","type":"div","attr":{"data-v-05924792":""},"style":{"alignItems":"center","marginTop":120},"event":["click"]}]}]


WXBridge.callAddElement

dom:{"ref":"9","type":"image","attr":{"data-v-05924792":"","src":"http://img1.vued.vanthink.cn/vued08aa73a9ab65dcbd360ec54659ada97c.png"},"style":{"width":360,"height":156}}

WXBridgeManager.callNative

WXBridgeManager.java

public int callNative(String instanceId, String tasks, String callback) {
    
    JSONArray array = JSON.parseArray(tasks);
    int size = array.size();
    if (size > 0) {
      try {
        JSONObject task;
        for (int i = 0; i < size; ++i) {
          task = (JSONObject) array.get(i);
          if (task != null && WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
            Object target = task.get(MODULE);
            if (target != null) {
              if (WXDomModule.WXDOM.equals(target)) {
                WXDomModule dom = getDomModule(instanceId);
                dom.callDomMethod(task, parseNanos);
              } else {
                JSONObject optionObj = task.getJSONObject(OPTIONS);
                callModuleMethod(instanceId, (String) target,
                    (String) task.get(METHOD), (JSONArray) task.get(ARGS), optionObj);
              }
            } else if (task.get(COMPONENT) != null) {
              //call component
              WXDomModule dom = getDomModule(instanceId);
              dom.invokeMethod((String) task.get(REF), (String) task.get(METHOD), (JSONArray) task.get(ARGS));
            } else {
              throw new IllegalArgumentException("unknown callNative");
            }
          }
        }
      } catch (Exception e) {
        // ignore
      }
    }
}

callNative有三个分支

  • dom.callDomMethod 构建dom
  • callModuleMethod 调用module的方法
  • dom.invokeMethod 调用compontent方法

ps: WXBridgeManager 有三个方法callNative,callNativeModule,callNativeComponent,其中callNative包含了callNativeModule,callNativeComponent,方法的职责设计的有点冗余啊

WXBridgeManager.callAddElement

public int callAddElement(String instanceId, String ref, String dom, String index, String callback) {

    JSONObject domObject = JSON.parseObject(dom);
    WXDomModule domModule = getDomModule(instanceId);
    DOMAction addElementAction = Actions.getAddElement(domObject, ref, Integer.parseInt(index));
    domModule.postAction(addElementAction, false);
}

domModule.postAction经过DomHandler进入到DomThread? 然后调用DomAction.executeDom。 DomAction子类如下图,常用的DomAction为CreateBodyAction和AddElementAction,两者都继承AbstractAddElementAction。包含共用方法executeDom和executeRender。executeDom主要的区别在于appendDomToTree的实现。

image.png

CreateBodyAction

public void executeDom(DOMActionContext context) {
   addDomInternal(context, mData);
}

protected void addDomInternal(DOMActionContext context, JSONObject dom) {
        WXDomObject domObject = WXDomObject.parse(dom, instance, null);
    appendDomToTree(context, domObject);
    domObject.traverseTree(
        context.getAddDOMConsumer(),
        context.getApplyStyleConsumer()
    );
    WXComponent component = createComponent(context, domObject);
    context.addDomInfo(domObject.getRef(), component);
    // 跳转到UIThread
    context.postRenderTask(this);
    addAnimationForDomTree(context, domObject);
}

  public void executeRender(RenderActionContext context) {
    WXComponent component = context.getComponent(WXDomObject.ROOT);
    component.createView();
    component.applyLayoutAndEvent(component);
    component.bindData(component);
    ...
    component.onRenderFinish(WXComponent.STATE_ALL_FINISH);
}

addDomInternal用大白话解释下,首先把dom字符串parse成对象domObject,接着把domObject加载到domTree中(appendDomToTree)。在CreateBodyAction中appendDomToTree会执行dom.ref=WXDomObject.ROOT已经更新宽高style,把root应有的style设置上去。然后createComponent生成的Dom就能应用上该style了。最后Dom构建完后postRenderTask,交给渲染层,这里会从DomThread切换到UIThread。

executeDom方法主要执行以下操作

  • 构建Dom节点,绑定节点属性等信息,生成Dom Tree
  • 根据Dom Tree生成Component Tree

executeRender方法主要执行以下操作

  • createView 生成dom对应的view,如WXDiv,WXImage,WXText等
  • applyLayoutAndEvent setLayout(包括width,height,top,left,right,bottom等)、padding、margin、事件绑定
  • bindData 绑定数据

AddElementAction

  public void executeDom(DOMActionContext context) {
    addDomInternal(context, mData); // 同上
}

AddElementAction.executeRender(RenderActionContext context) {
    WXComponent component = context.getComponent(mRef);
    WXVContainer parent = (WXVContainer) context.getComponent(mParentRef);
    parent.addChild(component, mAddIndex);
    parent.createChildViewAt(mAddIndex);
    component.applyLayoutAndEvent(component);
    component.bindData(component);
    ...
    component.onRenderFinish(WXComponent.STATE_ALL_FINISH);
}

addDomInternal同上,主要的差别在于appendDomToTree不同,CreateBodyAction是创建一个rootDom, AddElementAction是把改dom add到parentDom上。

executeRender类似,多了个 parent.addChild(component, mAddIndex); parent.createChildViewAt(mAddIndex);

附完整log

12-22 14:25:55.056 25639-25668/com.alibaba.weex D/weex: createInstance >>>> instanceId:1, options:{"bundleUrl":"http://your_current_IP:12580/examples/build/index.js","codeCachePath":"/data/user/0/com.alibaba.weex/files/v8/"}, data:null

12-22 14:25:55.057 25639-25668/com.alibaba.weex D/weex: callJS >>>> instanceId:1function:createInstance

12-22 14:25:55.061 25639-25639/com.alibaba.weex W/weex: Warning :Component tree has not build completely, onActivityResume can not be call!

12-22 14:25:55.125 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative >>>> instanceId:1, tasks:[{"module":"dom","method":"createBody","args":[{"ref":"_root","type":"div","attr":{"data-v-05924792":""},"style":{"alignItems":"center","marginTop":120},"event":["click"]}]}], callback:-1

12-22 14:25:55.141 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative::callAddElement >>>> instanceId:1, ref:_root, dom:{"ref":"9","type":"image","attr":{"data-v-05924792":"","src":"http://img1.vued.vanthink.cn/vued08aa73a9ab65dcbd360ec54659ada97c.png"},"style":{"width":360,"height":156}}, callback:undefined

12-22 14:25:55.145 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative::callAddElement >>>> instanceId:1, ref:_root, dom:{"ref":"11","type":"text","attr":{"data-v-05924792":""},"style":{"paddingTop":40,"paddingBottom":40,"fontSize":48}}, callback:undefined

12-22 14:25:55.148 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative >>>> instanceId:1, tasks:[{"module":"dom","method":"updateAttrs","args":["11",{"value":"Hello World"}]}], callback:-1

12-22 14:25:55.153 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative::callAddElement >>>> instanceId:1, ref:_root, dom:{"ref":"13","type":"text","attr":{"data-v-05924792":""},"style":{"paddingTop":20,"color":"#888888","fontSize":24}}, callback:undefined

12-22 14:25:55.155 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative >>>> instanceId:1, tasks:[{"module":"dom","method":"updateAttrs","args":["13",{"value":"Now, let's use vue to build your weex app."}]}], callback:-1

12-22 14:25:55.164 25639-25669/com.alibaba.weex D/weex: mInstanceId  1 batch used 7

12-22 14:25:55.169 25639-25668/com.alibaba.weex D/weex: [WXBridgeManager] callNative >>>> instanceId:1, tasks:[{"module":"dom","method":"createFinish","args":[]}], callback:-1

12-22 14:25:55.197 25639-25669/com.alibaba.weex D/weex: mInstanceId  1 batch used 16

12-22 14:25:55.244 25639-25639/com.alibaba.weex D/weex_perf: [render time]createView:2

12-22 14:25:55.247 25639-25639/com.alibaba.weex D/weex_perf: [render time]bind:2

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]firstScreenRenderFinished:196

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]   firstScreenJSFExecuteTime:70

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]   firstScreenCallNativeTime:30

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]       firstScreenJsonParseTime:18

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]   firstScreenBatchTime:23

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]       firstScreenCssLayoutTime:8

12-22 14:25:55.250 25639-25639/com.alibaba.weex D/weex_perf: [render time]       firstScreenApplyUpdateTime:3

12-22 14:25:55.251 25639-25639/com.alibaba.weex D/weex_perf: [render time]       firstScreenUpdateDomObjTime:3

12-22 14:25:55.257 25639-25639/com.alibaba.weex D/weex_perf: [render time]onRenderSuccess:203

12-22 14:25:55.257 25639-25639/com.alibaba.weex D/weex_perf: [render time]   invokeCreateInstance:118

12-22 14:25:55.257 25639-25639/com.alibaba.weex D/weex_perf: [render time]   TotalCallNativeTime:30

12-22 14:25:55.257 25639-25639/com.alibaba.weex D/weex_perf: [render time]       TotalJsonParseTime:18

12-22 14:25:55.258 25639-25639/com.alibaba.weex D/weex_perf: [render time]   TotalBatchTime:23

12-22 14:25:55.258 25639-25639/com.alibaba.weex D/weex_perf: [render time]       TotalCssLayoutTime:8

12-22 14:25:55.258 25639-25639/com.alibaba.weex D/weex_perf: [render time]       TotalApplyUpdateTime:3

12-22 14:25:55.258 25639-25639/com.alibaba.weex D/weex_perf: [render time]       TotalUpdateDomObjTime:3

12-22 14:25:55.258 25639-25639/com.alibaba.weex D/weex_perf: mComponentNum:4

12-22 14:25:55.281 25639-25668/com.alibaba.weex D/weex: callJS >>>> instanceId:1function:callJS tasks:[{"data":"1","type":2},{"data":"[{\"args\":[\"_root\",\"viewappear\",null,null],\"method\":\"fireEvent\"}]","type":3}]

12-22 14:25:55.323 25639-25639/com.alibaba.weex D/weex_perf: bizType:weex,pageName:AbstractWeexActivity,templateLoadTime0,localReadTime:0.0,JSLibInitTime:211,JSLibSize:0.0,templateUrlnull,JSTemplateSize:5.3564453125,communicateTime:118,screenRenderTime:196,firstScreenJSFExecuteTime:70,componentCount:4,syncTaskTime:0,pureNetworkTime:0,networkTime:0,actualNetworkTime:0,packageSpendTime:0,connectionType:null,requestType:null,initInvokeTime:11,initExecuteTime:14,SDKInitTime:380,totalTime:203.0,JSLibVersion:0.22.7,WXSDKVersion:0.9.4,errCode:null,renderFailedDetail:null,arg:,errMsg:

12-22 14:25:55.346 25639-25669/com.alibaba.weex D/weex: mInstanceId  1 batch used 5

12-22 14:32:34.108 25639-25639/com.alibaba.weex I/weex: Application onActivityPause()

12-22 14:32:34.109 25639-25639/com.alibaba.weex I/weex: Application to be in the backround

12-22 14:32:34.110 25639-25668/com.alibaba.weex D/weex: callJS >>>> instanceId:1function:callJS tasks:[{"data":"1","type":2},{"data":"[{\"args\":[\"_root\",\"viewdisappear\",null,null],\"method\":\"fireEvent\"}]","type":3}]

12-22 14:32:35.216 25639-25639/com.alibaba.weex I/weex: Application  to be in the foreground

12-22 14:32:35.221 25639-25668/com.alibaba.weex D/weex: callJS >>>> instanceId:1function:callJS tasks:[{"data":"1","type":2},{"data":"[{\"args\":[\"_root\",\"viewappear\",null,null],\"method\":\"fireEvent\"}]","type":3}]

12-22 14:32:35.237 25639-25639/com.alibaba.weex I/weex: Application onActivityPause()

12-22 14:32:35.238 25639-25639/com.alibaba.weex I/weex: Application to be in the backround

12-22 14:32:35.240 25639-25668/com.alibaba.weex D/weex: callJS >>>> instanceId:1function:callJS tasks:[{"data":"1","type":2},{"data":"[{\"args\":[\"_root\",\"viewdisappear\",null,null],\"method\":\"fireEvent\"}]","type":3}]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • 前言 在上篇文章里面谈了Weex在iOS客户端工作的基本流程。这篇文章将会详细的分析Weex是如何高性能的布局原生...
    一缕殇流化隐半边冰霜阅读 18,957评论 44 126
  • 目录一、介绍二、渲染引擎三、解析与DOM树构建四、渲染树构建五、布局六、绘制七、动态变化八、渲染引擎的线程九、CS...
    饥人谷_米弥轮阅读 2,452评论 0 10
  • 练习「每日千字文」就是每天写超过一千字的文章,命名为「每日千字文计划」。这是一件长期的训练,在写的过程中,会发现很...
    荷小音阅读 960评论 2 6
  • 杨园要疯了! 前一段时间,她莫名其妙的接到一个短信,说是李伟强借了别人的高利贷,希望她能催促还款。杨园拿着短信去问...
    影子倒了阅读 372评论 0 4