Stories

Detail Return Return

Android Weex 自定義 Component 指北

Weex 自定義 Component 開發這塊,官方文檔和網上示例都較少涉及。工作所需有所研究,總結此文以饗讀者。

基礎定義與註冊

如下述代碼所示,從 WXComponent 繼承出來以後,複寫四個構造器方法,就可以完成一個最簡單可跑當然也顯示不了任何東西的 WXComponet。

需要説明的是 WXComponent 可以指定泛型 T,T extends View,用於指定WXComponent hostView 根佈局的類型。這個還是指定的比較好,在某些進階用法中會需要這個類型。

public class DemoWXComponent extends WXComponent<T> {
    public DemoWXComponent(WXSDKInstance instance, WXVContainer parent,
                           int type,
                           BasicComponentData basicComponentData) {
        super(instance, parent, type, basicComponentData);
    }

    public DemoWXComponent(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy,
                           BasicComponentData basicComponentData) {
        super(instance, parent, instanceId, isLazy, basicComponentData);
    }

    public DemoWXComponent(WXSDKInstance instance, WXVContainer parent, boolean isLazy,
                           BasicComponentData basicComponentData) {
        super(instance, parent, isLazy, basicComponentData);
    }

    public DemoWXComponent(WXSDKInstance instance, WXVContainer parent,
                           BasicComponentData basicComponentData) {
        super(instance, parent, basicComponentData);
    }
}

使用這個 Component 之前,還需要把他註冊進 WXSDKEngine。如下所示:
一次註冊後,在Android程序銷燬之前,可以一直使用這個 Component。無需 unregister,WXSDKEngine 也沒有提供 unregister 方法,這是顯而易見的,因為當前還未產生任何實例。

WXSDKEngine.registerComponent("democomponent", DemoWXComponent.class);

值得一提的是 componet 名稱,儘量不要下劃線中劃線和大寫字母,否則可能會踩坑。

好,接下來是 Weex JS 代碼怎麼調用。無需 import,直接使用,只要 register 方法已經被執行過了,如下所示:

<democomponent />

如果想要設定 props 怎麼辦,如 <democomponent source=test/>。

那就在 Componet 中增加如下:

@WXComponentProp(name = "source")
public void setSource(String source) {
    mSource = source;
    // or do some things
}

weex 會根據外部傳入的 props,根據註解調用對應 props 的 set 方法。

生命週期

顯然,看了第一節,只能保證鏈路上 weex 自定義 Component 能跑起來,沒有做其他任何事情。那麼,為了能實現我們需要的渲染和其他邏輯,就需要了解 Weex Componet 的生命週期。這裏的生命週期,實質就是了解可 Override 的幾個 WXComponent 方法,和他們的被調用的時機。這一塊官方沒有任何文檔,全靠去 github 源碼中看和試。

必需 Override

initComponentHostView()

protected T initComponentHostView(@NonNull Context context) {
    // for example
    mComponentHostView = new FrameLayout(context);
    mComponentHostView.setId(R.id.fragment_content);
    return mComponentHostView;
}

用於生成根 View 返回給 Weex 來渲染。注意,不要在這裏進行任何響應外界設入的 props 的渲染,因為此時極大可能 props 還沒有被傳入。

可選 Override

bindData()

@Override
public void bindData(WXComponent component) {
    super.bindData(component);
    // 這裏進行 props 的響應渲染
}

super.bindData() 後即可響應 props 進行渲染,因為此時 props 的set方法都已經被調用過。

destroy()

@JSMethod
@Override
public void destroy() {
    super.destroy();
    // 進行自定義 Component 的必要銷燬邏輯
}

如果有額外需要銷燬的邏輯,需要寫在 destroy 之中。weex 會在退出 WXActivity 或其他等同的時候調用。值得一提的是,我一般加一個 @JSMethod 註解,以提供前端 Weex 開發一個主動銷燬的能力,避免需要的時候不能及時推代碼生效,而要等到發版。

暴露方法

上段其實已經提到,怎樣暴露一個 Component 方法給前端調用。如下所示:

@JSMethod
public void getDuration(JSCallback callback) {
    if (null != getCurrentShortVideoVh() && null != callback) {
        Map<String, Object> map = new HashMap<>(1);
        map.put("result", "value");
        callback.invoke(map);
    }
}

需要注意的是,直接把 void 改成返回值比如 boolean 然後試圖 return 是沒有用的,weex js 側收不到。因此,必須要去使用回調來給返回值。如上所示。

DOM

Weex 新內核(WeexCore)將 Dom 層和 Layout 引擎下沉到 C++ 層實現,移除 Java 層的 DomObject,提升渲染性能和內核的可通用性。因此,github 最新版不再可以獲取到 WXComponent 中的 DomObject。

Tricks:強轉

如果發現自定義 Component 的邏輯需要用到 Activity,而 WXComponent 只給你提供了 Context 的時候,不要慌,Weex 傳入的 Context 其實可以強轉 Activity。當然,以防萬一,記得用 instance of 保護一下。

同理,如果你想要彈出一個 Fragment,結果發現自己需要一個 FragmentActivity 來getSupportFragmentManager(),不要慌,weex 傳入的這個 Activity 也可以強轉為
FragmentActivity,同樣記得加 instance of 保護,否則業務掛了不算我的,因為這畢竟是文檔中的未定義行為。

user avatar
0 users favorite the story!

Post Comments

Some HTML is okay.