
在Vaadin应用中,当使用Grid组件展示数据时,我们常常希望能够异步加载部分内容,例如图片、详细描述等,以避免阻塞UI线程,提升用户体验。Grid提供了addComponentColumn方法,允许开发者为每一行数据动态生成自定义组件。结合Vaadin的Server Push机制(通过getDataCommunicator().enablePushUpdates()启用),理论上可以实现内容的异步更新。
然而,一个常见的问题是,即使后端数据获取方法被标记为异步(例如使用Spring的@Async注解返回ListenableFuture),前端Grid的渲染行为仍然可能表现出“同步”的特性:Grid的整体结构虽然立即显示,但addComponentColumn内部的组件内容却在所有异步操作完成后才一次性显示,而非逐个渐进式地填充。
这背后的原因在于,尽管异步方法本身在独立的线程中执行,但addComponentColumn的组件生成逻辑在被调用时,仍然会等待其内部的同步操作完成。如果异步方法的调用(例如获取ListenableFuture对象)本身在返回前包含了耗时操作(如示例中的Thread.sleep(3000)),或者组件的初始化逻辑在调用异步方法后等待其结果,那么Grid在渲染下一行之前,仍然会被当前行的组件生成逻辑所阻塞。
解决此问题的关键在于确保addComponentColumn的组件生成方法能够立即返回一个组件实例(即使是空的或占位符),而真正的异步数据加载和UI更新逻辑则完全在后台进行。
以下是优化的代码示例,展示了如何在getIconColumn方法中实现这一目标:
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.spring.annotation.EnableAsync; // Spring Async support, if applicable
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.AsyncResult;
import java.io.IOException;
import java.util.concurrent.Executors;
// 假设有一个服务类来处理异步逻辑
class MyAsyncService {
// 模拟耗时异步操作
@Async
public ListenableFuture<String> asyncLoadIcon(String entityName) {
try {
// 模拟网络请求或复杂计算
Thread.sleep(3000); // 模拟耗时
// 假设这里返回的是图片URL
return AsyncResult.forValue("https://example.com/images/" + entityName + ".jpg");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
return AsyncResult.forExecutionException(new RuntimeException("Async operation interrupted"));
}
}
}
public class GridAsyncLoadingExample {
private MyAsyncService rsCrawler = new MyAsyncService(); // 假设已注入或实例化
private void setupGrid() {
Grid<String> grid = new Grid<>();
grid.addComponentColumn(this::getIconColumn).setHeader("图片");
grid.setItems("item1", "item2", "item3", "item4", "item5");
// 启用Vaadin Push,允许服务器端异步更新推送到客户端
grid.getDataCommunicator().enablePushUpdates(Executors.newCachedThreadPool());
// add(grid); // 假设这里Grid被添加到某个Vaadin布局中
}
/**
* 为Grid的每一行生成图片列组件。
* 关键在于,图片组件立即返回,异步加载逻辑在独立线程中启动。
*
* @param entityName 实体名称,用于加载图片
* @return 初始为空的Image组件
*/
private Image getIconColumn(String entityName) {
Image image = new Image("", ""); // 立即创建一个空的Image组件
image.setHeight("150px");
image.setWidth("100px");
UI ui = UI.getCurrent(); // 获取当前UI实例,用于安全地更新UI
// 为每个异步加载任务启动一个新线程
// 这确保了getIconColumn方法可以立即返回Image组件,不阻塞Grid的渲染
new Thread(() -> {
rsCrawler.asyncLoadIcon(entityName)
.addCallback(
result -> ui.access(() -> image.setSrc(result)), // 成功时更新图片源
err -> ui.access(() -> Notification.show("加载图片失败: " + entityName + ", 错误: " + err.getMessage())) // 失败时显示通知
);
}).start(); // 启动新线程
return image; // 立即返回Image组件
}
}工作原理分析:
通过在addComponentColumn的组件生成逻辑中,将异步数据加载的启动操作放置到独立的线程中执行,我们可以有效地解除Grid渲染与实际数据获取之间的耦合。结合Vaadin的UI.access()和Server Push机制,这使得Grid能够实现平滑的渐进式内容加载,极大地改善了用户界面的响应性和感知性能。这种模式对于处理耗时操作并需要即时UI反馈的场景尤为重要。
以上就是优化Vaadin Grid异步内容加载:实现平滑渐进式渲染的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号