網頁

2010年1月7日 星期四

[GWT] 使用具有 Constructor 參數的 Widget

本文是根據這篇文章重新以中文說明 (Using a widget that requires constructor args)

下方是使用 uiBinder 建立 UI 的簡單例子:
<!-- UserDashboard.ui.xml -->

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
    xmlns:g='urn:import:com.google.gwt.user.client.ui'
    xmlns:my='urn:import:com.my.app.widgets' >

    <g:HTMLPanel>
        <my:CricketScores ui:field='scores' />
    </g:HTMLPanel>
</ui:UiBinder>
執行時 GWT 會偷偷的用 GWT.create() 建立 CricketScores 的實體 (經由Deferred Binding)。

但如果 CricketScores 的 Constructor 必需要傳入參數時,例如:
public CricketScores(String... teamNames) {...} 
這時 GWT.create() 就會出現錯誤:
[ERROR] com.my.app.widgets.CricketScores has no default (zero args) constructor. To fix this, you can define a @UiFactory method on the UiBinder's owner, or annotate a constructor of CricketScores with @UiConstructor.

這時候共有三種解決方法:
  1. 在 UserDashboard.java 中加入 @UiFactory method:
    // method name is insignificant
    @UiFactory CricketScores makeCricketScores() {
        return new CricketScores(teamNames);
    }
    
    @UiFactory method 的 method name 沒有特定的命名規則,GWT 會自動根據 return type 做判斷。也正因如此,如果一個 class 當中出現兩個相同 return type 的 @UiFactory method 時,GWT 也會顯示錯誤訊息:

    [ERROR] Duplicate factory in class UserDashboard for type CricketScores
  2. 使用 @UiConstructor:

    將 CricketScores 的 Constructor 加入 @UiConstructor annotation:
    public @UiConstructor CricketScores(String teamNames) {
        // ....
    } 
    
    並在 UserDashboard.ui.xml 內,CricketScores 標籤內加入與 Constructor 參數相同的屬性即可:
    <my:CricketScores ui:field='scores' teamNames='AUS, SAF, WA, QLD, VIC'/>
    
  3. 由 UiField(provided=true) 提供已建立好的物件:
    於 UserDashboard's Constructor 將 CricketScores 物件傳入,並以 @UiField 宣告 reference 變數指向 CricketScores 物件:
    public class UserDashboard extends Composite {
        interface MyUiBinder extends UiBinder<Widget, UserDashboard>;
        private static final MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
    
        @UiField(provided=true)
        final CricketScores cricketScores; // cannot be private
    
        public UserDashboard(CricketScores cricketScores) {
            this.cricketScores = cricketScores;
            initWidget(uiBinder.createAndBindUi(this));
        }
    }
    

沒有留言:

張貼留言