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主要的區(qū)別在于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會執(zhí)行dom.ref=WXDomObject.ROOT已經更新寬高style,把root應有的style設置上去。然后createComponent生成的Dom就能應用上該style了。最后Dom構建完后postRenderTask,交給渲染層,這里會從DomThread切換到UIThread。

executeDom方法主要執(zhí)行以下操作

  • 構建Dom節(jié)點,綁定節(jié)點屬性等信息,生成Dom Tree
  • 根據Dom Tree生成Component Tree

executeRender方法主要執(zhí)行以下操作

  • 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是創(chuàng)建一個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}]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • 前言 在上篇文章里面談了Weex在iOS客戶端工作的基本流程。這篇文章將會詳細的分析Weex是如何高性能的布局原生...
    一縷殤流化隱半邊冰霜閱讀 19,369評論 44 126
  • 目錄一、介紹二、渲染引擎三、解析與DOM樹構建四、渲染樹構建五、布局六、繪制七、動態(tài)變化八、渲染引擎的線程九、CS...
    饑人谷_米彌輪閱讀 2,513評論 0 10
  • 練習「每日千字文」就是每天寫超過一千字的文章,命名為「每日千字文計劃」。這是一件長期的訓練,在寫的過程中,會發(fā)現很...
    荷小音閱讀 1,168評論 2 6
  • 楊園要瘋了! 前一段時間,她莫名其妙的接到一個短信,說是李偉強借了別人的高利貸,希望她能催促還款。楊園拿著短信去問...
    影子倒了閱讀 450評論 0 4

友情鏈接更多精彩內容