2016年5月9日 星期一

GXT Component 的 onLoad 與 onShow 時機點

最近想要在 UI component 出現 / 消失的時候自動做一些事情,於是打算從 GXT Component 下手。不過怎麼寫怎麼有問題,只好寫 n 個 SSCCE 來確認一下,實驗結果紀錄於此。

基本認識

我關心這四個 method:

  • onLoad()
  • onUnload()
  • onShow()
  • onHide()

onLoad()onUnload() 是從 GWT 的 Widget 就定義的 method。理論上跟 onAttach()onDetach() 等意,就是這個 component 加入到 DOM(或是從 DOM 中移除)時會觸發的 method。不過 API 都強烈建議用 onLoad()onUnload() 了,就乖乖照辦。

onShow()onHide() 是 GXT Component 開始定義的 method,最常遇到的 caller 大概是 GXT Component 的 setVisible()(override UIObject)。

測試環境

  • JDK 1.7
  • GWT 2.7
  • GXT 3.1.0
  • Windows 7 (64bit)
  • Chrome 50

測試方式

我製造了兩個 component FooButton(繼承 TextButton) 跟 FooCP(繼承 ContentPanel)。分別 override 上述四個 method,例如:

    @Override
    protected void onLoad() {
        super.onLoad();
        Console.log("load " + getText());
    }

會需要 FooCP 是因為 AccordionLayoutContainerBorderLayoutContainer(在某些情況下)要求 child 是 ContentPanel

基本上我是用 UiBinder 撰寫 TestLayout(btw… TestLayout 繼承的是 GXT 的 Composite),然後 entry point 的 onModuleLoad() 這樣寫:

    Viewport vp = new Viewport();
    vp.add(new TestLayout());
    RootPanel.get().add(vp);

主要就是測試 FooButtonFooCP 作為各 layout container 還有 GXT TabPanel(見一次 murmur 一次,為啥這東西不是 container… ==”)的 child 時,上述四個 method 是否會觸發。

component 的行為(例如 collapse、close tab…)都是實際 UI 操作而不是程式呼叫 method。(希望這個差異不會炸出什麼新的問題)。

測試結果

注意:沒有測試所有已知的 layout container。

毫無反應區

下列 container 只會觸發 onLoad(),不會觸發 onShow()

  • AccordionLayoutContainer
  • CenterLayoutContainer
  • ContentPanel
  • FieldLabel
  • FieldSet(有設定 collapsible=true
  • FlowLayout
  • HBoxLayoutContainer
  • HorizontalLayoutContainer
  • NorthSouthContainer
  • SimpleContainer
  • VBoxLayoutContainer
  • VerticallayoutContainer

BorderLayoutContainer

center 的 child 只會在初始時觸發一次 onLoad(),其餘操作均無反應。

其他四個 region 在初始時會先依序觸發 onLoad(),然後再依序觸發 onShow()三次(如果不是用 UiBinder,而是用 Swing 的方式直接掛一個組好的 BorderLayoutContainerViewport,就會變兩次….. WTF?)

當某個 region 被 collapse 時,該 component 會觸發 onUnload()、但是不會觸發 onHide()。接著,其他還顯示的 region 會依序觸發 onShow()

當某個已經 collapse 的 region 展開回原狀時,會先觸發它的 onLoad(),然後再依序呼叫全部 region 的 onShow()

當某個已經 collapse 的 region 以 float 的方式出現 / 消失時,會觸發 onLoad() / onHide(),但是不會觸發其他 region 的 method。

當某個已經 collapse 的 region 以 float 的方式出現,然後再按下展開回原狀的按鈕,看起來是:

  1. 做 float region 消失的程序
  2. 做 region 恢復的程序

感覺有優化的空間

CardLayout

一開始會觸發所有 child 的 onHide(),然後才觸發 onLoad(),最後才是觸發 active widget 的 onShow()

切換 active widget 時,就是觸發對應 child 的 onShowonHide

TabPanel

(再 murmur 一次,為啥這玩意不是 layout container ==”)

初始時的觸發順序

  1. active widget 的 onHide()
  2. active widget 的 onShow()
  3. 其他 child 的 onHide()
  4. 全部 child 的 onLoad()

以下假設目前的 active widget 是 Foo1,另外還有一個 Foo2

  • 將 active widget 切換為 Foo2
    1. 觸發 Foo1onHide()
    2. 觸發 Foo2onShow()
  • 關掉有 Foo2 的 tab:
    1. 觸發 Foo2onUnload()
    2. 觸發 Foo2onShow()
  • 關掉有 Foo1 的 tab:
    1. 觸發 Foo1onUnload()
    2. 觸發 Foo1onShow()
    3. 觸發 Foo2onShow()

簡單地說,被關掉的 child 都會先觸發 onUnload() 然後再觸發 onShow()(WTF?)

結論(X) 詰譙(O)

其實不知道要有什麼結論… Orz

AccordionLayoutContainerFieldSet 並不會觸發 onShow() / onHide(),這點還可以接受。

CardLayoutContainer 的初始化步驟非常怪,都還沒掛上 DOM 那觸發 onHide() 是要幹麼?但是初始化只有一次,所以就算了。

BorderLayoutContainer 的 collapse 行為跟 onHide() 一點關係也沒有,但是會觸發其他 region 的 onShow()

TabPanel 可能是集各種詭異於一身的… 對,他還不是 container(謎之聲:你是要講幾次?)。關掉一個 tab 會觸發 onUnload() 這完全合情合理,但是為什麼還會再觸發 onShow() 阿阿阿阿…… Orz

我很願意相信,這背後都有好理由來支撐這一堆詭異行為;只是我更希望能有統一的行為模式,雖然會關心到這種 detail 程度的時候好像不多…

可是我就需要阿... [淚目]

2 則留言:

  1. 這看起來要 trace javascript code 才能看到全貌

    回覆刪除
  2. 不用耶... 因為基本上都已經包成 Java 的樣子了

    回覆刪除