Vaadin 23无需@PUSH实现异步加载占位内容的方案咨询
无@PUSH实现先显示进度条再异步加载Portlet内容
要解决iPhone上WebSocket失效的问题,同时保留「先显示进度条再加载内容」的交互,完全可以不用@PUSH,通过先推送进度条UI、再由客户端主动发起异步加载请求的方式实现,核心是拆分UIDL响应批次:
实现步骤
1. 先渲染进度条并强制刷到客户端
页面加载时,先把进度条添加到占位符,然后手动触发一次UIDL响应,让进度条单独发送到客户端显示:
// 视图初始化时的代码 ProgressBar progressBar = new ProgressBar(); progressBar.setIndeterminate(true); placeholderLayout.add(progressBar); // 强制刷新UI,让进度条先显示给用户 VaadinSession session = VaadinSession.getCurrent(); session.lock(); try { session.getCommunicationManager().flushUI(UI.getCurrent()); } finally { session.unlock(); }
这一步的关键是flushUI,它会把当前已有的UI变更单独打包成一个UIDL响应发送,不会等后续的内容加载完成再一起返回。
2. 客户端主动发起内容加载请求
进度条显示后,通过客户端JS触发服务器端的异步加载逻辑,全程由客户端发起XHR请求,无需服务器推送:
// 触发客户端调用服务器方法 UI.getCurrent().getPage().executeJs("$0.$server.loadPortletContent();", this); // 服务器端的回调方法,处理异步加载 @ClientCallable public void loadPortletContent() { // 用后台线程执行耗时的portlet加载逻辑,避免阻塞UI线程 CompletableFuture.runAsync(() -> { // 模拟加载过程(替换为实际的portlet加载代码) try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 加载完成后更新UI,替换进度条为portlet内容 UI.getCurrent().access(() -> { placeholderLayout.removeAll(); // 添加实际的portlet组件,例如: placeholderLayout.add(new VerticalLayout( new H3("Portlet 内容已加载"), new Label("这里是Portlet的具体内容") )); }); }); }
关键注意事项
- 手动
flushUI必须在VaadinSession锁定范围内执行,避免线程安全问题。 - 内容加载逻辑必须放在后台线程,不能阻塞UI线程,否则会导致后续UI响应卡住。
- 后台线程更新UI时,必须通过
UI.access()方法确保在UI上下文内操作。
内容的提问来源于stack exchange,提问作者alexanoid
相关产品推荐
相关产品推荐

