所有组件都是可序列化的(serializable),所以你可以为内存或其它存储器序列化组件,之后再拆解它们(so you can serialize components to the memory or other storage and de-serialize them later)。就像克隆,被拆解的组件不属于另一个页面(和桌面)(another page (and desktop))。它们也独立于被序列化的组件。如下所述,序列化可以被用于实现相似的克隆功能。
<vbox id="vb">
<listbox id="src" multiple="true" width="200px">
<listhead>
<listheader label="Population"/>
<listheader align="right" label="%"/>
</listhead>
<listitem value="A">
<listcell label="A. Graduate"/>
<listcell label="20%"/>
</listitem>
<listitem value="B">
<listcell label="B. College"/>
<listcell label="23%"/>
</listitem>
<listitem value="C">
<listcell label="C. High School"/>
<listcell label="40%"/>
</listitem>
</listbox>
<zscript>
int cnt = 0;
</zscript>
<button label="Clone">
<attribute name="onClick">
import java.io.*;
ByteArrayOutputStream boa = new ByteArrayOutputStream();
new ObjectOutputStream(boa).writeObject(src);
Listbox l = new ObjectInputStream(
new ByteArrayInputStream(boa.toByteArray())).readObject();
l.setId("dst" + ++cnt);
vb.insertBefore(l, self);
</attribute>
</button>
</vbox>
当然,使用clone方法克隆会有更好的性能,而序列化组件可以被用于不同的机器之间(crossing different machines)。
默认情况下,一个非序列化的实现会被用于表示一个会话(org.zkoss.zk.ui.Session)。使用非序列化实现的好处是不需要担心存储在一个组件内的值,例如Listitem's setValue,是否为可序列化的。
但是,若你想确认存储在组件内的所有值都是可序列化的,可以使用一个序列化的实现表示一个会话。
为了配置ZK使用序列化实现,你需要在WEB-INF/zk.xml
内配置factory-class元素,细节请参考the Developer's Reference 的附录B(Appendix B)。
存储在一个组件,页面,桌面或会话内的属性,变量和监听器也会被序列化,如果它们是可序列化的(且相应的组件,页面,桌面或会话会被序列化)。
为简化可序列化对象的实现,ZK会在序列化前和拆解之后调用序列化监听器,若实现了特定的接口。例如,你可以按如下方式为一个组件实现事件监听器。
public MyListener
implements EventListener, java.io.Serializable, ComponentSerializationListener {
private transient Component _target; //no need to serialize it
//ComponentSerializationListener//
public willSerialize(Component comp) {
}
public didDeserialize(Component comp) {
_target = comp; //restore it back
}
}
org.zkoss.zk.ui.util.ComponentSerializationListener接口被用于序列化一个组件时。类似的,PageSerializationListener,DesktopSerializationListen 和SessionSerializationListener 被分别用于序列化一个页面,桌面和会话时。