Hybrid开发框架一、Weex

Hybrid开发框架一、Weex前言最近开始试水Weex开发,使用这么长一段时间,感觉写Weex还是非常方便的。作为一个Android开发,免不了要追查一下weex的sdk源码。今天,就以WeexSDKforAndroid为例,分析SDK的认识WeexSDK源码https://github.com/alibaba/weex/tree/dev/android整体分析下拉,按照js文件的渲染过程,绘制出了下面…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

最近开始试水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的测量和布局过程;
Hybrid开发框架一、Weex

主要是通过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 time

        if (!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 style
        if (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,进行了帧率对比,数据如下:
Hybrid开发框架一、Weex

总结

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/190706.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • HTML注释标签以及注释快捷键的用法

    HTML注释标签以及注释快捷键的用法<html><head><title></title></head><body><!–注释内容–></body></html>…

  • win10下使用vs2015编译支持xp系统的libcurl

    win10下使用vs2015编译支持xp系统的libcurl在我的一篇博客中写了编译libcurl的,那种方式编译的curl动态库在win7到win10上可以使用,但是在xp系统里就不能使用了,接下来讲解一种方法可以在xp系统里使用cur。1编译openssl由于在perl官网里提供的perl版本没有dmake,因此使用我提供的perl5.24带dmake的包,下载地址。安装好perl后,可以尝试使用ppminstalldmake命令来进行安装dmake模块,在我电脑里无法安装,因此直接使用dmake离线包。将dmake.exe所在目录添加到系统pat

  • sklearn库的使用_导入turtle库的方法

    sklearn库的使用_导入turtle库的方法Sklearn库是基于Python的第三方库,它包括机器学习开发的各个方面。机器学习的开发基本分为六个步骤,1)获取数据,2)数据处理,3)特征工程,4)机器学习的算法训练(设计模型),5)模型评估,6)应用。机器学习的算法一般分为两种:一种既有目标值又有特征值的算法称之为监督学习,另一种只有特征值的算法称之为无监督学习。而监督学习还可以继续细分为分类算法和回归算法。1)获取数据⑤Sklearn中获取数据集使用的包为Sklearn.datasets,之后可以接load_*和fetch_*从Skle

  • windows开机后一键启动应用程序[通俗易懂]

    一键启动办公软件小工具分享每天上班前打开电脑总有一些固定的软件需要打开(如Foxmail、QQ等),那么一个一个启动非常会比较麻烦,下面分享一下小工具,稍微进行简单的配置后,便可以一键启动你想要打开的软件!

  • ArcGIS10地理信息系统教程—从初学到精通—笔记(持续更新)

    ArcGIS10地理信息系统教程—从初学到精通—笔记(持续更新)arcgis10初学到精通—重要操作整理第二章ArcGIS快速入门1.设置相对路径37页2.选择要素48页3.超链接51页4.测量第三章地理数据库geodatabase有以下三种类型:文件地理数据库,个人地理数据库、arcsed数据库文件数据库:以文件夹的形式保存、管理。文件数据库可以由多个用户使用,但是同一数据在同一时间只能由一个用户编辑。个人…

  • hdu 1394

    hdu 1394

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号