事件监听和处理2
<button label="Start Working Thread">
??????? <attribute name="onClick">
?????????????? timer.start();
?????????????? Label label = test.WorkingThread.asyncCreate(desktop);
?????????????? main.appendChild(label);
?????????????? timer.stop();
??????? </attribute>
</button>
<timer id="timer" runing="false" delay="1000" repeats="true"/>
</window>
注意我们需要使用timer来真正恢复被挂起的事件监听器(onclick)。这看起来是多余的,但是归因于
http的限制:为了保持web页面在浏览器中的alive,当事件处理进程被挂起的时候我们必须返回回应。
然后,工作线程完成了工作,唤醒了事件监听器,http的请求已经gone了。因此,我们需要”piggyback
”这个结果,这就是timer被使用的原因。
更准确的来说,当工作进程唤醒了事件监听器,ZK只是把它加到一个等待队列中。当另一个http请求到
达的时候,监听器才真正的恢复。(在上面的例子中,是onTimer事件)
在这个简单里例子中,我们对onTimer事件什么都没做。对于一个sophisticated应用,你可以使用它来
返回处理的状态。
另一个事例:没有挂起和恢复
没有挂起和恢复来执行一个长时间的操作是可能的。当同步代码对于调试来说太复杂的情况下是有用的
。
主意很简单。工作进程在一个临时空间里保存结果,然后onTimer事件监听器将结果弹出到桌面。
//WorkingThread2
package test;
public class WorkingThread2 extends Thread
{
private static int _cnt;
private final Desktop _desktop;
private final List _result;
public WorkThread2(Desktop desktop,List result)
{
??????? _desktop = desktop;
??????? _result=result;
}
public void run(){
??????? _result.add(new Label("Execute "+ ++_cnt));
}
}
然后,在onTimer事件监听器上面追加labels
?
<window id = "main" title="working thread2">
<zscript>
int numpending = 0;
List result=Collections.synchronizedList(new LinkedList());
</zscript>
<button label="start working thread">
??????? <attribute name="onClick">
?????????????? ++numpending;
?????????????? timer.start()
?????????????? new test.workingthread2(desktop,result).start();
??????? </attribute>
</button>
<timer id="timer" running="false" delay="1000" repeats="true">
??????? <attribute name="onTimer">
?????????????? while(!result.isEmpty())
?????????????? {
????????????????????? main.appendChild(result.remove(0));
????????????????????? --numpending;
?????????????? }
?????????????? if(numpending==0)time.stop();
??????? </attribute>
</timer>
</window>
初始和清除事件处理线程
在处理每个事件之前初始化
一个事件监听器是在一个事件处理线程中执行的。有时,你不得不在处理所有事件之前初始该线程。
一个典型的例子是初始认证所使用的线程。一些j2ee或者web容器在thread local storage中存储着认证
信息,因此它们可以在需要时自动进行重复认证。
为了进行事件处理线程的初始化,你需要在web-inf/zk.xml文件注册一个继承自
org.zkoss.zk.ui.event.EventThreadInit接口的类。
一旦进行了注册,在开始一个事件处理线程之前,在主线程中一个指定类的实例就被创建了。然后在处
理其他事情之前,该实例的init方法在事件处理线程的上下文中被调用了。
注意那个构造体和init方法是在不同的线程中被调用的,因此开发者可以从一个线程获得线程独立的数
据发送到另一个线程。
下面是jboss的认证机制的例子。在这个例子中,我们在构造体中获得储藏在servlet线程中的信息。然
后,我们在init方法调用的时候初始事件处理线程。
import java.security.Principal;
import org.jboss.security.SecurityAssociation;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventThreadInit;
public class JBossEventThreadInit implements EventThreadInit
{
?????? private final Principal _principal;
?????? private final Object _credential;
?????? public JBossEventThreadInit()
?????? {
????????????? _principal=SecurityAssociation.getPrincipal();
????????????? _credential=SecurityAssociation.getCredential();
?????? }
?????? public void init(Component comp,Event evt)
?????? {
????????????? SecurityAssociation.setPrincipal(_principal);
????????????? SecurityAssociation.setCredential(_credential);
?????? }
}
然后在web-inf/zk,xml中,如下进行注册:
<zk>
?????? <listener>
????????????? <listener-class>JBossEventThreadInit</listener-class>
?????? </listener>
</zk>
在处理完每个事件后清除
同样的,你可能不得不在处理完一个事件后清除一个事件处理进程。
典型的例子是关闭一个transaction,如果它没有被适当的关闭。
为了清除一个事件处理线程,你需要注册一个实现org.zkoss.zk.ui.event.EventThreadCleanup接口的
监听类,然后在web-inf/zk.xml中注册。
<zk>
?????? <listener>
????????????? <listener-class>my.MyEventThreadCleanup </listener-class>
?????? </listener>
</zk>