And UI.access around the part that modifies the UI components. And I suggest to forget the DataProvider API as it just complicates things. Try this (with @Push as suggested by @knoobie ):
package org.vaadin.firitin;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.router.Route;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
@Route
public class GridProblem extends VerticalLayout {
private Grid<String> grid;
private List<String> strings = new ArrayList<>();
public GridProblem() {
grid = new Grid<>();
grid.setSizeFull();
grid.setItems(strings);
grid.setHeight("400px");
grid.addColumn(r -> r).setTextAlign(ColumnTextAlign.END).setHeader("Value").setSortable(true);
add(grid);
UI ui = UI.getCurrent();
futureStream().forEach(future -> {
future.thenAccept(result -> {
ui.access(() -> {
System.out.println(result);
strings.add(result);
grid.setItems(strings);
});
});
});
}
public Stream<CompletableFuture<String>> futureStream() {
List<CompletableFuture<String>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(CompletableFuture.supplyAsync(() -> {
int nextInt = new Random().nextInt(3);
try {
TimeUnit.SECONDS.sleep(nextInt);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "" + nextInt;
}));
}
return list.stream();
}
}
That’s weird, the default should be automatic in Vaadin 14 too. Maybe it is defined in some other location to be “manual”, like directly in the Push annotation that you might have have somewhere.
Instead of providing a “Command” to the UI::access call, use the “ErrorHandlingCommand”, this allows to handle the error directly within your problematic code.
I wonder why the exception is eaten then Could it be that everything actually works, but there is still an issue with Push configuration and the changes are just not reflected to the browser side? You could check if things start to work if you configure polling with e.g. UI.setPollInterval(1000).
Otherwise I’d check with debugger what is going on, but would need a reduced test case for that.
BTW. That getUI() method is a bit of a trap that many fall into (if it is the one from Component), and I’d even call it a design flaw. That is not thread safe, so you should call it only within properly synced call (some framework initiated call or within UI.access). So store the UI reference somewhere earlier and then use that reference instead the getUI() method. I don’t believe this to be the issue here though…
I want to add result rows to Grid asap. Also i’d like to keep loading indicator shown till all futures are completed.
If I comment out the line CompletableFuture.allOf(futures).join();
new values apears in the Grid as expected, but loading indicator is missing.
other way, with this line (CompletableFuture.allOf(futures).join()) new results won’t be added to Grid till all the futures are completed
I’ve checked in debug UI.push() is’nt called for some reason.
I understand that CompletableFuture.allOf(futures).join(); locks current thread to wait. Probably I should remove CompletableFuture.allOf(futures).join() and show loading indicator programmatically.