Weex源碼分析之Dom構(gòu)建&Render

流程

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

渲染實(shí)例

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有三個(gè)分支

  • dom.callDomMethod 構(gòu)建dom
  • callModuleMethod 調(diào)用module的方法
  • dom.invokeMethod 調(diào)用compontent方法

ps: WXBridgeManager 有三個(gè)方法callNative,callNativeModule,callNativeComponent,其中callNative包含了callNativeModule,callNativeComponent,方法的職責(zé)設(shè)計(jì)的有點(diǎn)冗余啊

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經(jīng)過DomHandler進(jìn)入到DomThread? 然后調(diào)用DomAction.executeDom。 DomAction子類如下圖,常用的DomAction為CreateBodyAction和AddElementAction,兩者都繼承AbstractAddElementAction。包含共用方法executeDom和executeRender。executeDom主要的區(qū)別在于appendDomToTree的實(shí)現(xiàn)。

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);
    // 跳轉(zhuǎn)到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已經(jīng)更新寬高style,把root應(yīng)有的style設(shè)置上去。然后createComponent生成的Dom就能應(yīng)用上該style了。最后Dom構(gòu)建完后postRenderTask,交給渲染層,這里會從DomThread切換到UIThread。

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

  • 構(gòu)建Dom節(jié)點(diǎn),綁定節(jié)點(diǎn)屬性等信息,生成Dom Tree
  • 根據(jù)Dom Tree生成Component Tree

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

  • createView 生成dom對應(yīng)的view,如WXDiv,WXImage,WXText等
  • applyLayoutAndEvent setLayout(包括width,height,top,left,right,bottom等)、padding、margin、事件綁定
  • bindData 綁定數(shù)據(jù)

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)建一個(gè)rootDom, AddElementAction是把改dom add到parentDom上。

executeRender類似,多了個(gè) 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}]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內(nèi)容

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