深刻Weex系列(十)Weex SDK可優化細節思考

一、前言

在上一篇文章中咱們介紹了Weex SDK源碼中可借鑑的細節,那麼如今的Weex SDK已是最優的嗎?做爲技術RD,咱們心中必定要有敬畏:藝無止境,學習的過程當中逐漸反思,尋找最優解。那麼咱們今天就來講說Weex SDK中有哪些能夠優化的細節。前端

二、反射獲取方法

你們知道對於Weex來講,JS引擎與Native的交互本質上就是方法的調用,最終調用的時候必然是反射無疑,可是方法的獲取也是反射這一點存在很大優化空間。webpack

先回憶下咱們使用Module組件的方法:git

  • 繼承WXModule;
  • 編寫函數體;
  • 給函數體打上註解@JSMethod;

而這些被打上註解的函數則能夠拿來與Js進行交互,咱們回憶下Module註冊的代碼,分別有Native的註冊和Js的註冊,註冊有一步是獲取Module組件中打上註解的方法:github

@Override
  public String[] getMethods() {
    if (mMethodMap == null) {
      generateMethodMap();
    }
    Set<String> keys = mMethodMap.keySet();
    return keys.toArray(new String[keys.size()]);
  }
  
  private void generateMethodMap() {
    if(WXEnvironment.isApkDebugable()) {
      WXLogUtils.d(TAG, "extractMethodNames:" + mClazz.getSimpleName());
    }
    HashMap<String, Invoker> methodMap = new HashMap<>();
    try {
      for (Method method : mClazz.getMethods()) {// 拿到方法
        // iterates all the annotations available in the method
        for (Annotation anno : method.getDeclaredAnnotations()) {// 方法是否被打上註解
          if (anno != null) {
            if(anno instanceof JSMethod) {
              JSMethod methodAnnotation = (JSMethod) anno;
              String name = JSMethod.NOT_SET.equals(methodAnnotation.alias())? method.getName():methodAnnotation.alias();
              methodMap.put(name, new MethodInvoker(method, methodAnnotation.uiThread()));// 封裝成MethodInvoker對象
              break;
            }else if(anno instanceof WXModuleAnno) {
              WXModuleAnno methodAnnotation = (WXModuleAnno)anno;
              methodMap.put(method.getName(), new MethodInvoker(method,methodAnnotation.runOnUIThread()));
              break;
            }
          }
        }
      }
    } catch (Throwable e) {
      WXLogUtils.e("[WXModuleManager] extractMethodNames:", e);
    }
    mMethodMap = methodMap;
  }  
複製代碼

能夠看到,Module註冊的過程一定是相對耗時的,而Module越多時間也越長,應用啓動階段註冊的話尤其明顯。而對於另外一個組件Component基本也是同樣的,只不過多了個註解@Component:web

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
  boolean lazyload() default true;
}
複製代碼

區別在於:對於Native註冊,會有懶加載的判斷,不過效果通常,由於Js端註冊前已經生成一次了:緩存

@Override
  public void loadIfNonLazy() {
    Annotation[] annotations = mClz.getDeclaredAnnotations();
    for (Annotation annotation :
      annotations) {
      if (annotation instanceof Component){
        // 懶加載則暫時跨過這步
        if(!((Component) annotation).lazyload() && mMethodInvokers == null){
          generate();
        }
        return;
      }
    }
  }
複製代碼

那麼反射消耗性能加上耗時的缺點應該如何解決呢?這裏提供兩條解決途徑供參考:bash

  • 對Weex進行異步初始化,絕大多數應用使用Weex不會是整個App都由Weex完成,那麼只要能保證Weex的初始化在使用以前完成便可;這點很容易作到畢竟App都有閃屏的時間能夠利用;
  • 參考EventBus不一樣版本的改進,咱們也能夠將Weex的運行時註解改成編譯時註解,這樣就將在運行時的反射工做挪換到編譯時,這種方式顯然更好,也不須要再進行異步初始化;

三、適配的問題

對於Weex,它默認的將顯示的寬度設置爲750px做爲適配的標準。微信

@Deprecated
  public static float getRealPxByWidth(float pxValue) {
     return getRealPxByWidth(pxValue,750);
  }
  
  public static float getRealPxByWidth(float pxValue,int customViewport) {
    if (Float.isNaN(pxValue)) {
      return pxValue;
    }
    if (mUseWebPx) {
      return (float) Math.rint(pxValue);
    } else {
      float realPx = (pxValue * getScreenWidth() / customViewport);
      return realPx > 0.005 && realPx < 1 ? 1 : (float) Math.rint(realPx);
    }
  }
複製代碼

那提一個開發中的細節問題:我怎麼知道須要在Vue的佈局代碼中寫多少px呢?若是UI同窗給出的不是750標準就須要本身使用公尺去計算。網絡

解決思路:異步

  • 規範使用統一的頁面適配保證好比出圖按照750或者720(修改Weex適配的代碼);
  • 修改Weex的webpack-loader,仍是使用類如Android原生dp同樣的佈局單位(須要前端同窗配合寫個工具);

四、基礎能力不夠好

這個以前在Module的源碼解析中其實提到過,好比網絡請求的能力,不論是線程池的使用仍是對緩存、協議等的支持都很通常。類如別的一些基礎能力好比Stroage等模塊也是同樣。

不過這條屬於苛責,以前也總結過對於Weex來講咱們實際上只須要保存其Js引擎與Native的交互能力便可,別的都屬於Weex爲了吸引開發者而作的簡略能力。現實的要求是把這些代碼去掉,本身橋接原生原有的能力,縮減Apk的方法數。

五、其它

  • CSS的支持度不夠完善,一些效果在Web上的顯示和Native上不同,這要求調試儘可能在Native;
  • 關於文檔,不能否認Weex的思路和SDK代碼都很是優秀,可是文檔就相對通常了,有些屬於錯誤的;有些屬於過於簡單,好比對網絡請求,沒有Post請求的示例,對Component的自定義,沒有ViewGroup的示例,有點拈輕怕重的嫌疑;

歡迎持續關注Weex源碼分析項目:Weex-Analysis-Project

歡迎關注微信公衆號:按期分享Java、Android乾貨!

歡迎關注
相關文章
相關標籤/搜索