流程
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的实现。
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}]