所有组件都是可序列化的(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
被分别用于序列化一个页面,桌面和会话时。