ZK 10中doAfterCompose()调用Messagebox.show()致页面渲染停滞问题
ZK 10升级后Messagebox弹出时后台页面未渲染的解决方案
问题背景
从ZK 8.5.2.1升级至适配Jakarta的最新ZK 10热修复版本后,在doAfterCompose()方法中弹出模态Messagebox时出现异常:旧版本中弹出Messagebox的同时,后台页面会完整渲染;但ZK 10中,尽管Java代码仍在执行,Messagebox背后的页面却未完成渲染。禁用Messagebox后页面可正常渲染,且未使用已废弃的事件线程处理机制。
相关代码片段:
// ...doAfterCompose() - check if its read or unread and offer user to mark as read if (!TrueFalseConverter.instance().nvlFrom(entity.getLPrectena())) { Messagebox.show(Labels.getLabel("diaries.make.msg.question.order.set_read.text"), Labels.getLabel("diaries.make.msg.question.order.set_read.title"), Messagebox.YES | Messagebox.NO, Messagebox.QUESTION, new SerializableEventListener<Event>() { @Override public void onEvent(Event event) throws Exception { if (Messagebox.ON_YES.equals(event.getName())) { entity.setLPrectena(TrueFalseConverter.instance().to(Boolean.TRUE)); app.r.ovdenObjednavkyRepository.store(entity); } } }); } // ...continue with components creation and render the page
问题分析
ZK 10对UI渲染流程做了调整:在组件初始化阶段(如doAfterCompose)调用Messagebox.show()时,模态对话框的渲染会优先抢占响应资源,导致后续的组件创建和页面渲染逻辑虽执行,但对应的UI更新被延迟至Messagebox关闭后才触发。而ZK 8.5的处理逻辑是先完成页面基础渲染,再弹出Messagebox。
解决方案
要恢复旧版本的页面渲染行为,核心思路是先完成页面渲染,再异步弹出Messagebox,以下是两种可行方案:
方案1:使用Clients.defer()延迟弹出
利用ZK的Clients.defer()方法,将Messagebox的弹出逻辑延迟到当前页面渲染周期完成后执行,确保页面先完成渲染再弹出对话框:
// ...doAfterCompose() - check if its read or unread and offer user to mark as read if (!TrueFalseConverter.instance().nvlFrom(entity.getLPrectena())) { // 延迟到页面渲染完成后弹出Messagebox Clients.defer(new Runnable() { @Override public void run() { Messagebox.show(Labels.getLabel("diaries.make.msg.question.order.set_read.text"), Labels.getLabel("diaries.make.msg.question.order.set_read.title"), Messagebox.YES | Messagebox.NO, Messagebox.QUESTION, new SerializableEventListener<Event>() { @Override public void onEvent(Event event) throws Exception { if (Messagebox.ON_YES.equals(event.getName())) { entity.setLPrectena(TrueFalseConverter.instance().to(Boolean.TRUE)); app.r.ovdenObjednavkyRepository.store(entity); } } }); } }); } // ...continue with components creation and render the page
方案2:使用EventQueues.schedule()异步执行
通过ZK事件队列调度,将Messagebox的弹出放在当前渲染周期之后的异步任务中:
// ...doAfterCompose() - check if its read or unread and offer user to mark as read if (!TrueFalseConverter.instance().nvlFrom(entity.getLPrectena())) { EventQueues.lookup(EventQueues.APPLICATION, EventQueues.DESKTOP, true) .schedule(new EventListener<Event>() { @Override public void onEvent(Event event) throws Exception { Messagebox.show(Labels.getLabel("diaries.make.msg.question.order.set_read.text"), Labels.getLabel("diaries.make.msg.question.order.set_read.title"), Messagebox.YES | Messagebox.NO, Messagebox.QUESTION, new SerializableEventListener<Event>() { @Override public void onEvent(Event event) throws Exception { if (Messagebox.ON_YES.equals(event.getName())) { entity.setLPrectena(TrueFalseConverter.instance().to(Boolean.TRUE)); app.r.ovdenObjednavkyRepository.store(entity); } } }); } }); } // ...continue with components creation and render the page
原理说明
两种方案均通过延迟Messagebox的弹出时机,让页面先完成当前渲染周期内的组件创建与UI渲染,再触发模态对话框,从而实现与ZK 8.5一致的效果:页面完整渲染后再弹出Messagebox,用户可正常看到后台页面内容。
内容的提问来源于stack exchange,提问作者Worsik
相关产品推荐
相关产品推荐

