Hybrid开发框架一、Weex

2024-05-07 05:08
文章标签 开发 框架 hybrid weex

本文主要是介绍Hybrid开发框架一、Weex,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

最近开始试水Weex开发,使用这么长一段时间,感觉写Weex还是非常方便的。作为一个Android开发,免不了要追查一下weex的sdk源码。今天,就以Weex SDK for Android为例,分析SDK的

认识Weex SDK

源码https://github.com/alibaba/weex/tree/dev/android

整体分析下拉,按照js文件的渲染过程,绘制出了下面架构图:

sdk_framework

WEEX文件渲染过程

为了更加详细的说明整个渲染过程,我对源码进行了分析。并结合示例,进行了日志分析;比如,我们要开发如下一个简单的组件(红色方框内):
demo

那么,我们的wxc-title.we源码为:

<!-- wxc-title.we created by mochuan.zhb-->
<template><div class="container"><image class="image" src="{{item.pic}}"></image><text class="text">{{item.name}}</text></div>
</template><style>.container {position: relative;flex-direction: row;width: 750px;height: 60px;align-items: center;}.image {margin-left: 100px;width: 45px;height: 45px;}.text {margin-left: 10px;font-size: 28px;color: #444444;}
</style><script>module.exports = {data: {item: {pic: '//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png',name: '当地玩乐'}},methods: {}}
</script>

上述.we文件经过weex编译之后,生成的js文件,经过格式化如下:

...
([function (module, exports) {module.exports = {"type": "div","classList": ["container"],"children": [{"type": "image","classList": ["image"],"attr": {"src": function () {return this.item.pic}}},{"type": "text","classList": ["text"],"attr": {"value": function () {return this.item.name}}}]}
}, function (module, exports) {module.exports = {"container": {"position": "relative","flexDirection": "row","width": 750,"height": 60,"alignItems": "center"},"image": {"marginLeft": 100,"width": 45,"height": 45},"text": {"marginLeft": 10,"fontSize": 28,"color": "#444444"}}
}, function (module, exports) {module.exports = function (module, exports, __weex_require__) {'use strict';module.exports = {data: function () {return {item: {pic: '//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png',name: '当地玩乐'}}},methods: {}};}}
]);

上述分别使用了三个function,对template、style和script进行了封装;那么,这个文件是怎么被weex sdk执行并解析,最终生成结构化的View的呢?

渲染过程

时序图1:

从扫码开始,首先经历如下过程;依次经过readerPage,createInstance,一直到WXBridge的exeJs方法;也就是说,最终,Java通过调用native的exeJs方法,来执行js文件的。

https://img.alicdn.com/tps/TB1CKC.OFXXXXXkXpXXXXXXXXXX-2530-840.png
 

时序图2:

紧接着时序图1:执行到JNI层的Java_com_taobao_weex_bridge_WXBridge_execJS方法;

https://img.alicdn.com/tps/TB1K2uBOFXXXXbnaXXXXXXXXXXX-2374-1352.png

然后js通过native调用WXBridge的callNative方法,达到js调用Java代码的目的;
JNI层的部分代码如下:

jint Java_com_taobao_weex_bridge_WXBridge_execJS(JNIEnv *env, jobject this1, jstring jinstanceid,jstring jnamespace, jstring jfunction,jobjectArray jargs) {v8::HandleScope handleScope;v8::Isolate::Scope isolate_scope(globalIsolate);v8::Context::Scope ctx_scope(V8context);v8::TryCatch try_catch;int length = env->GetArrayLength(jargs);v8::Handle<v8::Value> obj[length];jclass jsObjectClazz = (env)->FindClass("com/taobao/weex/bridge/WXJSObject");for (int i = 0; i < length; i++) {jobject jArg = (env)->GetObjectArrayElement(jargs, i);jfieldID jTypeId = (env)->GetFieldID(jsObjectClazz, "type", "I");jint jTypeInt = env->GetIntField(jArg, jTypeId);jfieldID jDataId = (env)->GetFieldID(jsObjectClazz, "data", "Ljava/lang/Object;");jobject jDataObj = env->GetObjectField(jArg, jDataId);if (jTypeInt == 1) {jclass jDoubleClazz = (env)->FindClass("java/lang/Double");jmethodID jDoubleValueId = (env)->GetMethodID(jDoubleClazz, "doubleValue", "()D");jdouble jDoubleObj = (env)->CallDoubleMethod(jDataObj, jDoubleValueId);obj[i] = v8::Number::New((double) jDoubleObj);env->DeleteLocalRef(jDoubleClazz);} else if (jTypeInt == 2) {jstring jDataStr = (jstring) jDataObj;obj[i] = jString2V8String(env, jDataStr);} else if (jTypeInt == 3) {v8::Handle<v8::Value> jsonObj[1];v8::Handle<v8::Object> global = V8context->Global();json = v8::Handle<v8::Object>::Cast(global->Get(v8::String::New("JSON")));json_parse = v8::Handle<v8::Function>::Cast(json->Get(v8::String::New("parse")));jsonObj[0] = jString2V8String(env, (jstring) jDataObj);v8::Handle<v8::Value> ret = json_parse->Call(json, 1, jsonObj);obj[i] = ret;}env->DeleteLocalRef(jDataObj);env->DeleteLocalRef(jArg);}env->DeleteLocalRef(jsObjectClazz);const char *func = (env)->GetStringUTFChars(jfunction, 0);v8::Handle<v8::Object> global = V8context->Global();v8::Handle<v8::Function> function;v8::Handle<v8::Value> result;if (jnamespace == NULL) {function = v8::Handle<v8::Function>::Cast(global->Get(v8::String::New(func)));result = function->Call(global, length, obj);}else {v8::Handle<v8::Object> master = v8::Handle<v8::Object>::Cast(global->Get(jString2V8String(env,jnamespace)));function = v8::Handle<v8::Function>::Cast(master->Get(jString2V8String(env,jfunction)));result = function->Call(master, length, obj);}if (result.IsEmpty()) {assert(try_catch.HasCaught());ReportException(globalIsolate, &try_catch, jinstanceid, func);env->ReleaseStringUTFChars(jfunction, func);env->DeleteLocalRef(jfunction);return false;}env->ReleaseStringUTFChars(jfunction, func);env->DeleteLocalRef(jfunction);return true;
}
}

详细代码,可参见github:https://github.com/alibaba/weex_v8core/blob/master/jni/v8core/com_taobao_weex_bridge_WXBridge.cpp
 

时序图3:createBody&generateComponentTree

接着上面的时序图,开始做页面的创建;关键的代码在WXRenderStatement中的createBodyOnDomThread,该方法通过创建跟布局的mGodComponent,通过递归generateComponentTree生成Component的逻辑树结构;然后,在WXRenderStatement的createBody方法中,生成View,绑定属性和数据;具体如下图所示:

https://img.alicdn.com/tps/TB1OTG7OFXXXXbYXpXXXXXXXXXX-2528-1184.png
 

时序图4:addElement


https://img.alicdn.com/tps/TB1xVe5OFXXXXc3XpXXXXXXXXXX-2508-1002.png
 

时序图5:callNative调用Module


https://img.alicdn.com/tps/TB1MSi4OFXXXXb9XpXXXXXXXXXX-1438-860.png
 

调用过程日志记录

以上面的weex页面为例:使用PlayGround扫码之后的调用过程中的日志为:

12-04 15:51:04.705: D/weex(30188): ###render in WXSDKInstance. pageName = WXPageActivity,template = /******/ (function(modules) { // webpackBootstrap
12-04 15:51:04.705: D/weex(30188): ###createInstance in WXSDKManager code = /******/ (function(modules) { // webpackBootstrap
12-04 15:51:04.710: D/weex(30188): ###createInstance in WXBrideManager instanceId = 3,template = /******/ (function(modules) { // webpackBootstrap
12-04 15:51:04.710: D/weex(30188): ###invokeCreateInstance in WXBrideManager instanceId = 3,template = /******/ (function(modules) { // webpackBootstrap
12-04 15:51:04.725: D/weex(30188): ###execJS instanceId = 3,namespace = null,function = createInstance,args = [{"data":"3","type":2},{"data":"/******/ (function(modules) { // webpackBootstrap\n .......
12-04 15:51:04.740: D/weex(30188): ###callNative in WXBridge instanceId = 3,tasks = [{"module":"dom","method":"createBody","args":[{"ref":"_root","type":"div","attr":{},"style":{"position":"relative","flexDirection":"row","width":750,"height":60,"alignItems":"center"}}]}],callback = -1
12-04 15:51:04.740: D/weex(30188): ###callDomMethod to create component...task = {"args":[{"attr":{},"ref":"_root","style":{"alignItems":"center","flexDirection":"row","height":60,"position":"relative","width":750},"type":"div"}],"method":"createBody","module":"dom"}
12-04 15:51:04.745: D/weex(30188): ###callDomMethod task = {"args":[{"attr":{},"ref":"_root","style":{"alignItems":"center","flexDirection":"row","height":60,"position":"relative","width":750},"type":"div"}],"method":"createBody","module":"dom"}
12-04 15:51:04.745: D/weex(30188): ###createBody element = {"attr":{},"ref":"_root","style":{"alignItems":"center","flexDirection":"row","height":60,"position":"relative","width":750},"type":"div"}
12-04 15:51:04.745: D/weex(30188): ###handleMessage in WXDomHandler...what = 0,obj = {"args":[{"attr":{},"ref":"_root","style":{"alignItems":"center","flexDirection":"row","height":60,"position":"relative","width":750},"type":"div"}],"instanceId":"3"}
12-04 15:51:04.750: D/weex(30188): ###createBodyOnDomThread in WXRenderStatement dom = layout: {left: 0.0, top: 0.0, width: 0.0, height: 0.0, direction: LTR}direction =INHERIT
12-04 15:51:04.750: D/weex(30188): ###createView in WXComponent className = WXDiv
12-04 15:51:04.755: D/weex(30188): ###generateComponentTree in WXRenderStatement component = WXDiv
12-04 15:51:04.755: D/weex(30188): ###callAddElement in WXBridge instanceId = 3,ref = _root,dom = {"ref":"153","type":"image","attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"style":{"marginLeft":100,"width":45,"height":45}},index=-1,callback = -1
12-04 15:51:04.755: D/weex(30188): ###callAddElement in WXBridgeManager instanceId = 3,ref = _root,dom = {"ref":"153","type":"image","attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"style":{"marginLeft":100,"width":45,"height":45}},index = -1,callback = -1
12-04 15:51:04.760: D/weex(30188): ###addElement parentRef = _root,element = {"attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"ref":"153","style":{"height":45,"marginLeft":100,"width":45},"type":"image"},index = -1
12-04 15:51:04.760: D/weex(30188): ###handleMessage in WXDomHandler...what = 3,obj = {"args":["_root",{"attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"ref":"153","style":{"height":45,"marginLeft":100,"width":45},"type":"image"},-1],"instanceId":"3"}
12-04 15:51:04.760: D/weex(30188): ###callAddElement in WXBridge instanceId = 3,ref = _root,dom = {"ref":"154","type":"text","attr":{"value":"当地玩乐"},"style":{"marginLeft":10,"fontSize":28,"color":"#444444"}},index=-1,callback = -1
12-04 15:51:04.765: D/weex(30188): ###callAddElement in WXBridgeManager instanceId = 3,ref = _root,dom = {"ref":"154","type":"text","attr":{"value":"当地玩乐"},"style":{"marginLeft":10,"fontSize":28,"color":"#444444"}},index = -1,callback = -1
12-04 15:51:04.765: D/weex(30188): ###addElement parentRef = _root,element = {"attr":{"value":"当地玩乐"},"ref":"154","style":{"color":"#444444","fontSize":28,"marginLeft":10},"type":"text"},index = -1
12-04 15:51:04.765: D/weex(30188): ###addDom in WXDomManager instanceId = 3,parentRef = _root,element = {"attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"ref":"153","style":{"height":45,"marginLeft":100,"width":45},"type":"image"},index = -1
12-04 15:51:04.765: D/weex(30188): ###callNative in WXBridge instanceId = 3,tasks = [{"module":"dom","method":"createFinish","args":[]}],callback = -1
12-04 15:51:04.770: D/weex(30188): ###addDom in WXDomStatement dom = {"attr":{"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"},"ref":"153","style":{"height":45,"marginLeft":100,"width":45},"type":"image"},parentRef = _root,index = -1
12-04 15:51:04.770: D/weex(30188): ###createComponentOnDomThread in WXRenderManager dom = layout: {left: 0.0, top: 0.0, width: 0.0, height: 0.0, direction: LTR}direction =INHERIT
12-04 15:51:04.770: D/weex(30188): ###createComponentOnDomThread in WXRenderStatement dom = layout: {left: 0.0, top: 0.0, width: 0.0, height: 0.0, direction: LTR}direction =INHERIT
12-04 15:51:04.770: D/weex(30188): ###generateComponentTree in WXRenderStatement component = WXImage
12-04 15:51:04.775: D/weex(30188): ###callDomMethod to create component...task = {"args":[],"method":"createFinish","module":"dom"}
12-04 15:51:04.775: D/weex(30188): ###handleMessage in WXDomHandler...what = 255,obj = null
12-04 15:51:04.775: D/weex(30188): ###callDomMethod task = {"args":[],"method":"createFinish","module":"dom"}
12-04 15:51:04.775: D/weex(30188): ###createFinish
12-04 15:51:04.775: D/weex(30188): ###handleMessage in WXDomHandler...what = 3,obj = {"args":["_root",{"attr":{"value":"当地玩乐"},"ref":"154","style":{"color":"#444444","fontSize":28,"marginLeft":10},"type":"text"},-1],"instanceId":"3"}
12-04 15:51:04.775: D/weex(30188): ###addDom in WXDomManager instanceId = 3,parentRef = _root,element = {"attr":{"value":"当地玩乐"},"ref":"154","style":{"color":"#444444","fontSize":28,"marginLeft":10},"type":"text"},index = -1
12-04 15:51:04.780: D/weex(30188): ###addDom in WXDomStatement dom = {"attr":{"value":"当地玩乐"},"ref":"154","style":{"color":"#444444","fontSize":28,"marginLeft":10},"type":"text"},parentRef = _root,index = -1
12-04 15:51:04.780: D/weex(30188): ###createComponentOnDomThread in WXRenderManager dom = layout: {left: 0.0, top: 0.0, width: 0.0, height: 0.0, direction: LTR}direction =INHERIT
12-04 15:51:04.780: D/weex(30188): ###createComponentOnDomThread in WXRenderStatement dom = layout: {left: 0.0, top: 0.0, width: 0.0, height: 0.0, direction: LTR}direction =INHERIT
12-04 15:51:04.785: D/weex(30188): ###generateComponentTree in WXRenderStatement component = WXText
12-04 15:51:04.785: D/weex(30188): ###handleMessage in WXDomHandler...what = 9,obj = {"instanceId":"3"}
12-04 15:51:04.790: D/weex(30188): ###handleMessage in WXDomHandler...what = 255,obj = null
12-04 15:51:04.820: D/weex(30188): ###createBody in WXRenderStatement component = WXDiv
12-04 15:51:04.820: D/weex(30188): ###createView in WXComponent className = WXDiv
12-04 15:51:04.820: D/weex(30188): ###applyLayoutAndEvent in WXComponent className = WXDiv
12-04 15:51:04.825: D/weex(30188): ###bindData in WXContainer 
12-04 15:51:04.825: D/weex(30188): ###bindData in WXComponent = WXDiv
12-04 15:51:04.825: D/weex(30188): ###updateProperties in props = {"alignItems":"center","backgroundColor":"#ffffff","flexDirection":"row","height":60,"position":"relative","width":750}
12-04 15:51:04.825: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.825: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.825: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.825: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.825: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.830: D/weex(30188): ###setProperty in WXComponent = WXDiv
12-04 15:51:04.830: D/weex(30188): ###updateProperties in props = {}
12-04 15:51:04.830: D/weex(30188): ###addComponent in WXRenderManager instanceId = 3,component = WXImage,parentRef = _root,index = -1
12-04 15:51:04.830: D/weex(30188): ###addComponent in WXRenderStatement to start render the component to view...
12-04 15:51:04.835: D/weex(30188): ###createView in WXComponent className = WXImage
12-04 15:51:04.835: D/weex(30188): ###applyLayoutAndEvent in WXComponent className = WXImage
12-04 15:51:04.835: D/weex(30188): ###bindData in WXComponent = WXImage
12-04 15:51:04.835: D/weex(30188): ###updateProperties in props = {"height":45,"marginLeft":100,"width":45}
12-04 15:51:04.835: D/weex(30188): ###setProperty in WXComponent = WXImage
12-04 15:51:04.835: D/weex(30188): ###setProperty in WXComponent = WXImage
12-04 15:51:04.835: D/weex(30188): ###setProperty in WXComponent = WXImage
12-04 15:51:04.840: D/weex(30188): ###updateProperties in props = {"src":"//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png"}
12-04 15:51:04.840: D/weex(30188): ###addComponent in WXRenderManager instanceId = 3,component = WXText,parentRef = _root,index = -1
12-04 15:51:04.840: D/weex(30188): ###addComponent in WXRenderStatement to start render the component to view...
12-04 15:51:04.840: D/weex(30188): ###createView in WXComponent className = WXText
12-04 15:51:04.840: D/weex(30188): ###applyLayoutAndEvent in WXComponent className = WXText
12-04 15:51:04.840: D/weex(30188): ###bindData in WXComponent = WXText
12-04 15:51:04.840: D/weex(30188): ###updateProperties in props = {"color":"#444444","fontSize":28,"marginLeft":10}
12-04 15:51:04.845: D/weex(30188): ###setProperty in WXComponent = WXText
12-04 15:51:04.845: D/weex(30188): ###updateProperties in props = {"value":"当地玩乐"}
12-04 15:51:04.850: D/weex(30188): ###execJS instanceId = 3,namespace = null,function = callJS,args = [{"data":"3","type":2},{"data":"[{\"args\":[\"_root\",\"viewappear\",null,null],\"method\":\"fireEvent\"}]","type":3}]
12-04 15:51:04.850: D/weex(30188): ###callNative in WXBridge instanceId = 3,tasks = [{"module":"dom","method":"updateFinish","args":[]}],callback = -1
12-04 15:51:04.855: D/weex(30188): ###callDomMethod to create component...task = {"args":[],"method":"updateFinish","module":"dom"}
12-04 15:51:04.855: D/weex(30188): ###callDomMethod task = {"args":[],"method":"updateFinish","module":"dom"}
12-04 15:51:04.855: D/weex(30188): ###updateFinish
12-04 15:51:04.860: D/weex(30188): ###handleMessage in WXDomHandler...what = 11,obj = {"instanceId":"3"}
12-04 15:51:04.875: D/weex(30188): ###handleMessage in WXDomHandler...what = 255,obj = null

View绘制过程对比

首先,我们看一下Android原声的View绘制过程:
android_view

主要是measure测量大小,layout确定位置。

其次,我们对比一下Weex的WXComponent的测量和布局过程;


主要是通过CSSLayout进行测量,使用view的setLayoutParams来确定View在父ViewGroup中的位置。

核心代码如下:

Spacing parentPadding = mParent.getDomObject().getPadding();Spacing parentBorder = mParent.getDomObject().getBorder();Spacing margin = mDomObj.getMargin();int realWidth = (int) mDomObj.getLayoutWidth();int realHeight = (int) mDomObj.getLayoutHeight();int realLeft = (int) (mDomObj.getLayoutX() - parentPadding.get(Spacing.LEFT) -parentBorder.get(Spacing.LEFT));int realTop = (int) (mDomObj.getLayoutY() - parentPadding.get(Spacing.TOP) -parentBorder.get(Spacing.TOP));int realRight = (int) margin.get(Spacing.RIGHT);int realBottom = (int) margin.get(Spacing.BOTTOM);if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealTop == realTop) {return;}if (mParent != null) {mAbsoluteY = (int) (mParent.mAbsoluteY + mDomObj.getLayoutY());mAbsoluteX = (int) (mParent.mAbsoluteX + mDomObj.getLayoutX());}//calculate first screen timeif (!mInstance.mEnd && !(mHost instanceof ViewGroup) && mAbsoluteY + realHeight > mInstance.getWeexHeight() + 1) {mInstance.firstScreenRenderFinished();}if (mHost == null) {return;}MeasureOutput measureOutput = measure(realWidth, realHeight);realWidth = measureOutput.width;realHeight = measureOutput.height;if (mHost instanceof WXCircleIndicator) {FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(realWidth, realHeight);params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);return;}//fixed styleif (mDomObj.isFixed() && mInstance.getRootView() != null) {if (mHost.getParent() instanceof ViewGroup) {ViewGroup viewGroup = (ViewGroup) mHost.getParent();viewGroup.removeView(mHost);}FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);params.width = realWidth;params.height = realHeight;params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);mInstance.getRootView().addView(mHost);if (WXEnvironment.isApkDebugable()) {WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout :" + realLeft + " " + realTop + " " + realWidth + " " + realHeight);WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout Left:" + mDomObj.getStyles().getLeft() + " " + (int) mDomObj.getStyles().getTop());}return;}...else if (mParent.getRealView() instanceof BounceRecyclerView && this instanceof WXCell) {RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) mHost.getLayoutParams();if (params == null)params = new RecyclerView.LayoutParams(realWidth, realHeight);params.width = realWidth;params.height = realHeight;params.setMargins(realLeft, 0, realRight, 0);mHost.setLayoutParams(params);} else if (mParent.getRealView() instanceof BaseBounceView && this instanceof WXBaseRefresh) {LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(realWidth, realHeight);realTop = (int) (parentPadding.get(Spacing.TOP) - parentBorder.get(Spacing.TOP));params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);} else if (mParent.getRealView() instanceof FrameLayout) {FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(realWidth, realHeight);params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);} else if (mParent.getRealView() instanceof LinearLayout) {LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(realWidth, realHeight);params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);} else if (mParent.getRealView() instanceof ScrollView) {ScrollView.LayoutParams params = new ScrollView.LayoutParams(realWidth, realHeight);params.setMargins(realLeft, realTop, realRight, realBottom);mHost.setLayoutParams(params);}

View渲染过程对比

渲染过程对比:
weex_android

weex的渲染过程,上面已经写的比较清晰了;对于Android,其渲染过程大致可以总结为:
1.编译期使用aapt对xml进行编译,生成二进制的xml
2.运行时,使用XmlBlock构建XmlPullParser,通过LayoutInflater的rInflater进行解析,最终生成View;
具体详细过程,可以参看我的另外一遍博客:Android-LayoutInflater效率分析及源码跟踪

那么,两种方式的解析效率差异有多大呢?官方的数据如下:
 

weex_ss

帧率对比

目前以飞猪app的购物车为例:Weex,Native,以及投放到手淘的H5,进行了帧率对比,数据如下:

总结

weex无论在createBody、addElement,还是在callNative中对Module的调用,都还有很多优化空间。比如,可以把部分运行时的工作,搬到编译期做,这样可以加快页面的渲染时间;在渲染之后,滑动过程中的帧率对比发现,weex和native基本相近,比H5的表现要好。

这篇关于Hybrid开发框架一、Weex的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966407

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者