Android Weex 渲染逻辑分析

一.背景

最近学习了下Weex Android的渲染逻辑,这里做个总结,加深印象。

总体上说 Weex Android的渲染代码分为三个部分:

  1. bridge。 运行于 js bridge thread,主要负责与native层进行数据交互。
  2. dom。运行于 dom thread,主要负责解析渲染命令(JSON)生成控件,解析属性,生成控件树结构等。
  3. render。运行于 render thread (也就是UI thread),主要负责控件的渲染逻辑。

ok,话不多说,直接看源码分析。(源码基于Weex release 0.16版本)

二.源码分析

一般来说,Weex渲染的使用方式都是从

WXSDKInstance的Render方法开始,那么我们就从这里开始分析:

1.render方法最终都会调用到,renderInternal( String pageName,String template, Map<String, Object> options, String jsonInitData,WXRenderStrategy flag)

private void renderInternal(String pageName,
                              String template,
                              Map<String, Object> options,
                              String jsonInitData,
                              WXRenderStrategy flag){
    if (mRendered || TextUtils.isEmpty(template)) {  //如果渲染过,或者模板为空,直接返回。
      return;
    }

    WXLogUtils.d("WXSDKInstance", "Start render page: " + pageName);

    if (WXTracing.isAvailable()) {  //性能采集相关,可以不关注。
      WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1);
      traceEvent.traceId = mExecJSTraceId;
      traceEvent.iid = mInstanceId;
      traceEvent.tname = "JSThread";
      traceEvent.ph = "B";
      traceEvent.submit();
      mRenderStartNanos = System.nanoTime();
    }

    ensureRenderArchor(); //确保RenderContainer存在,没有的话,会新建。

    Map<String, Object> renderOptions = options;
    if (renderOptions == null) {
      renderOptions = new HashMap<>();
    }

    if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) {
      renderOptions.put("dynamicMode", "true");
      renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag);
      return;
    }

    mWXPerformance.pageName = pageName;
    mWXPerformance.JSTemplateSize = template.length() / 1024f;

    mRenderStartTime = System.currentTimeMillis();
    mRenderStrategy = flag;

    WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName);

    WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData);
    mRendered = true;

    if (TextUtils.isEmpty(mBundleUrl)) {
      mBundleUrl = pageName;
    }
  }

其中 ensureRenderArchor() 方法主要是确保RenderContainer存在,RenderContainer是Weex渲染后的View的Parent容器,继承于FrameLayout。

ensureRenderArchor方法如下:

private void ensureRenderArchor(){
    if(mRenderContainer == null){
      if (getContext() != null) {
        mRenderContainer = new RenderContainer(getContext());
        mRenderContainer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        mRenderContainer.setBackgroundColor(Color.TRANSPARENT);
        mRenderContainer.setSDKInstance(this);
        mRenderContainer.addOnLayoutChangeListener(this);
      }
    }
  }

renderInternal 方法 最终会 调用到  WXSDKManager的createInstance方法:

2. WXSDKManager.createInstance()

 void createInstance(WXSDKInstance instance, String code, Map<String, Object> options, String jsonInitData) {
    mWXRenderManager.registerInstance(instance); //
    mBridgeManager.createInstance(instance.getInstanceId(), code, options, jsonInitData);
    if (mLifeCycleCallbacks != null) {
      for (InstanceLifeCycleCallbacks callbacks : mLifeCycleCallbacks) {  //Weex instance相关生命周期的回调。
        callbacks.onInstanceCreated(instance.getInstanceId());
      }
    }
  }

其中mWXRenderManager是渲染相关的管理器,它的registerInstance方法如下:

public void registerInstance(WXSDKInstance instance) {
    mRegistries.put(instance.getInstanceId(), new RenderActionContextImpl(instance));
  }

会生成一个RenderActionContextImpl,并且把它和WXSDKInstance绑定在一起。

之后调用了BridgeManager的createInstance方法,继续往下看。

3. BridgeManager.createInstance()

/**
   * Create instance.
   */
  public void createInstance(final String instanceId, final String template,
                             final Map<String, Object> options, final String data) {
    final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);  //实际上是从上述RenderActionContextImpl里面获取到的。
    if (instance == null) {
      WXLogUtils.e("WXBridgeManager", "createInstance failed, SDKInstance is not exist");
      return;
    }
    if (TextUtils.isEmpty(instanceId)
        || TextUtils.isEmpty(template) || mJSHandler == null) {
      instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance fail!"); //渲染出错回调
      return;
    }

    if (!isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) { //没有初始化成功,并且不是连接到Debug模式下
      instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance fail!");
      post(new Runnable() {  // post 到 js thread
        @Override
        public void run() {
          initFramework("");//初始化Framework,Framework实际上是main.js文件
        }
      }, instanceId);
      return;
    }

    WXModuleManager.createDomModule(instance);  //注册WXDomModule,提供部分DOM相关的方法实现。
    post(new Runnable() {
      @Override
      public void run() {
        long start = System.currentTimeMillis();
        invokeCreateInstance(instance, template, options, data);
        final long totalTime = System.currentTimeMillis() - start;
        WXSDKManager.getInstance().postOnUiThread(new Runnable() {

          @Override
          public void run() {
            instance.createInstanceFinished(totalTime);
          }
        }, 0);
      }
    }, instanceId);
  }

一般来说js framework会在Weex初始化的时候进行初始化,但是如果js framework没有初始化成功,那么会触发方法:initFramework方法,该方法如下:

private void initFramework(String framework) {
    if (!isJSFrameworkInit()) { //没有初始化过,方法内部通过mInit变量判断。
      if (TextUtils.isEmpty(framework)) {
        // if (WXEnvironment.isApkDebugable()) {
        WXLogUtils.d("weex JS framework from assets");
        // }
        framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication()); //asset目录下的main.js
      }
      if (TextUtils.isEmpty(framework)) {
        mInit = false;
        commitJSFrameworkAlarmMonitor(IWXUserTrackAdapter.JS_FRAMEWORK, WXErrorCode.WX_ERR_JS_FRAMEWORK, "JS Framework is empty!");
        return;
      }
      try {
        if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
          WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart();
        }

        long start = System.currentTimeMillis();
        String crashFile = "";
        try {
          crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
        } catch (Exception e) {
          e.printStackTrace();
        }
        boolean pieSupport = true;
        try {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            pieSupport = false;
          }
        } catch (Exception e) {
          e.prin
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值