1、前言
在上一篇文章中我們介紹了Weex SDK原始碼中可借鑑的細節,那麼現在的Weex SDK已經是最優的嗎?作為技術RD,我們心中一定要有敬畏:藝無止境,學習的過程中逐漸反思,尋找最優解。那麼我們今天就來說說Weex SDK中有哪些可以優化的細節。
2、反射獲取方法
大家知道對於Weex來說,JS引擎與Native的互動本質上就是方法的呼叫,最終呼叫的時候必然是反射無疑,但是方法的獲取也是反射這一點存在很大優化空間。
先回憶下我們使用Module元件的方法:
- 繼承WXModule;
- 編寫函式體;
- 給函式體打上註解@JSMethod;
而這些被打上註解的函式則可以拿來與Js進行互動,我們回憶下Module註冊的程式碼,分別有Native的註冊和Js的註冊,註冊有一步是獲取Module元件中打上註解的方法:
@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:
@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;
}
}
}
複製程式碼
那麼反射消耗效能加上耗時的缺點應該如何解決呢?這裡提供兩條解決途徑供參考:
- 對Weex進行非同步初始化,絕大多數應用使用Weex不會是整個App都由Weex完成,那麼只要能保證Weex的初始化在使用之前完成即可;這點很容易做到畢竟App都有閃屏的時間可以利用;
- 參考EventBus不同版本的改進,我們也可以將Weex的執行時註解改為編譯時註解,這樣就將在執行時的反射工作挪換到編譯時,這種方式顯然更好,也不需要再進行非同步初始化;
3、適配的問題
對於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一樣的佈局單位(需要前端同學配合寫個工具);
4、基礎能力不夠好
這個之前在Module的原始碼解析中其實提到過,比如網路請求的能力,不管是執行緒池的使用還是對快取、協議等的支援都很一般。類如別的一些基礎能力比如Stroage等模組也是一樣。
不過這條屬於苛責,之前也總結過對於Weex來說我們實際上只需要儲存其Js引擎與Native的互動能力即可,別的都屬於Weex為了吸引開發者而做的簡略能力。現實的要求是把這些程式碼去掉,自己橋接原生原有的能力,縮減Apk的方法數。
5、其它
- CSS的支援度不夠完善,一些效果在Web上的顯示和Native上不一樣,這要求除錯儘量在Native;
- 關於文件,不可否認Weex的思路和SDK程式碼都非常優秀,但是文件就相對一般了,有些屬於錯誤的;有些屬於過於簡單,比如對網路請求,沒有Post請求的示例,對Component的自定義,沒有ViewGroup的示例,有點避重就輕的嫌疑;
歡迎持續關注Weex原始碼分析專案:Weex-Analysis-Project
歡迎關注微信公眾號:定期分享Java、Android乾貨!
![歡迎關注](https://i.iter01.com/images/7f61be090f5473267d29bcf04af7d126b865e321d40d756b4310918675181a75.jpg)