Weex Android SDK源碼分析

前言

最近開(kāi)始試水Weex開(kāi)發(fā),使用這么長(zhǎng)一段時(shí)間,感覺(jué)寫(xiě)Weex還是非常方便的谋减。作為一個(gè)Android開(kāi)發(fā),免不了要追查一下weex的sdk源碼扫沼。今天出爹,就以Weex SDK for Android為例,分析SDK的

認(rèn)識(shí)Weex SDK

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

整體分析下拉充甚,按照js文件的渲染過(guò)程以政,繪制出了下面架構(gòu)圖:

sdk_framework
sdk_framework

WEEX文件渲染過(guò)程

為了更加詳細(xì)的說(shuō)明整個(gè)渲染過(guò)程,我對(duì)源碼進(jìn)行了分析伴找。并結(jié)合示例盈蛮,進(jìn)行了日志分析;比如技矮,我們要開(kāi)發(fā)如下一個(gè)簡(jiǎn)單的組件(紅色方框內(nèi)):

飛豬app購(gòu)物車(chē)
飛豬app購(gòu)物車(chē)

那么抖誉,我們的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: '當(dāng)?shù)赝鏄?lè)'
            }
        },
        methods: {

        }
    }
</script>

上述.we文件經(jīng)過(guò)weex編譯之后,生成的js文件衰倦,經(jīng)過(guò)格式化如下:

...
([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: '當(dāng)?shù)赝鏄?lè)'
                        }
                    }
                },
                methods: {}
            };
        }
    }
]);

上述分別使用了三個(gè)function袒炉,對(duì)template、style和script進(jìn)行了封裝樊零;那么我磁,這個(gè)文件是怎么被weex sdk執(zhí)行并解析孽文,最終生成結(jié)構(gòu)化的View的呢?

渲染過(guò)程

時(shí)序圖1:

從掃碼開(kāi)始夺艰,首先經(jīng)歷如下過(guò)程芋哭;依次經(jīng)過(guò)readerPage,createInstance郁副,一直到WXBridge的exeJs方法减牺;也就是說(shuō),最終存谎,Java通過(guò)調(diào)用native的exeJs方法拔疚,來(lái)執(zhí)行js文件的。


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


時(shí)序圖2:

緊接著時(shí)序圖1:執(zhí)行到JNI層的Java_com_taobao_weex_bridge_WXBridge_execJS方法;


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



然后js通過(guò)native調(diào)用WXBridge的callNative方法既荚,達(dá)到j(luò)s調(diào)用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;
}
}

詳細(xì)代碼,可參見(jiàn)github:https://github.com/alibaba/weex_v8core/blob/master/jni/v8core/com_taobao_weex_bridge_WXBridge.cpp

時(shí)序圖3:createBody&generateComponentTree

接著上面的時(shí)序圖固以,開(kāi)始做頁(yè)面的創(chuàng)建墩虹;關(guān)鍵的代碼在WXRenderStatement中的createBodyOnDomThread嘱巾,該方法通過(guò)創(chuàng)建跟布局的mGodComponent,通過(guò)遞歸generateComponentTree生成Component的邏輯樹(shù)結(jié)構(gòu);然后憨琳,在WXRenderStatement的createBody方法中,生成View旬昭,綁定屬性和數(shù)據(jù)篙螟;具體如下圖所示:


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


時(shí)序圖4:addElement



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


時(shí)序圖5:callNative調(diào)用Module



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


調(diào)用過(guò)程日志記錄

以上面的weex頁(yè)面為例:使用PlayGround掃碼之后的調(diào)用過(guò)程中的日志為:

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":"http://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":"http://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":"http://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":"http://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":"當(dāng)?shù)赝鏄?lè)"},"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":"當(dāng)?shù)赝鏄?lè)"},"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":"當(dāng)?shù)赝鏄?lè)"},"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":"http://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":"http://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":"當(dāng)?shù)赝鏄?lè)"},"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":"當(dāng)?shù)赝鏄?lè)"},"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":"當(dāng)?shù)赝鏄?lè)"},"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":"http://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":"當(dāng)?shù)赝鏄?lè)"}
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繪制過(guò)程對(duì)比

首先,我們看一下Android的View繪制過(guò)程:

android_view
android_view

主要是measure測(cè)量大小问拘,layout確定位置遍略。

其次,我們對(duì)比一下Weex的WXComponent的測(cè)量和布局過(guò)程骤坐;

</img>


主要是通過(guò)CSSLayout進(jìn)行測(cè)量绪杏,使用view的setLayoutParams來(lái)確定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渲染過(guò)程對(duì)比

渲染過(guò)程對(duì)比:


weex_android
weex_android

weex的渲染過(guò)程纽绍,上面已經(jīng)寫(xiě)的比較清晰了蕾久;對(duì)于Android,其渲染過(guò)程大致可以總結(jié)為:

1.編譯期使用aapt對(duì)xml進(jìn)行編譯拌夏,生成二進(jìn)制的xml
2.運(yùn)行時(shí)僧著,使用XmlBlock構(gòu)建XmlPullParser,通過(guò)LayoutInflater的rInflater進(jìn)行解析障簿,最終生成View盹愚;
具體詳細(xì)過(guò)程,可以參看我的另外一遍博客:Android-LayoutInflater效率分析及源碼跟蹤

那么站故,兩種方式的解析效率差異有多大呢皆怕?官方的數(shù)據(jù)如下:

weex_ss

幀率對(duì)比

目前以飛豬app的購(gòu)物車(chē)為例:Weex,Native,以及投放到手淘的H5愈腾,進(jìn)行了幀率對(duì)比朗兵,數(shù)據(jù)如下:


zhenlv
zhenlv

總結(jié)

weex無(wú)論在createBody、addElement顶滩,還是在callNative中對(duì)Module的調(diào)用余掖,都還有很多優(yōu)化空間。比如礁鲁,可以把部分運(yùn)行時(shí)的工作盐欺,搬到編譯期做,這樣可以加快頁(yè)面的渲染時(shí)間仅醇;在渲染之后冗美,滑動(dòng)過(guò)程中的幀率對(duì)比發(fā)現(xiàn),weex和native基本相近析二,比H5的表現(xiàn)要好粉洼。

附錄

weex版知乎日?qǐng)?bào):https://github.com/nuptboyzhb/WeexZhihuDaily

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市叶摄,隨后出現(xiàn)的幾起案子属韧,更是在濱河造成了極大的恐慌,老刑警劉巖蛤吓,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宵喂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡会傲,警方通過(guò)查閱死者的電腦和手機(jī)锅棕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)淌山,“玉大人裸燎,你說(shuō)我怎么就攤上這事∑靡桑” “怎么了德绿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)王浴。 經(jīng)常有香客問(wèn)我脆炎,道長(zhǎng),這世上最難降的妖魔是什么氓辣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任秒裕,我火速辦了婚禮,結(jié)果婚禮上钞啸,老公的妹妹穿的比我還像新娘几蜻。我一直安慰自己喇潘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布梭稚。 她就那樣靜靜地躺著颖低,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弧烤。 梳的紋絲不亂的頭發(fā)上忱屑,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音暇昂,去河邊找鬼莺戒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛急波,可吹牛的內(nèi)容都是我干的从铲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼澄暮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼名段!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起泣懊,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤伸辟,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后嗅定,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體自娩,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡用踩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年渠退,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脐彩。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碎乃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠奸,到底是詐尸還是另有隱情梅誓,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布佛南,位于F島的核電站梗掰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嗅回。R本人自食惡果不足惜及穗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绵载。 院中可真熱鬧埂陆,春花似錦苛白、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鹃栽,卻和暖如春躏率,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背民鼓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工禾锤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摹察。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓恩掷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親供嚎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子黄娘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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