Skip to content

Commit b2acf69

Browse files
mlopezFCpaodb
authored andcommitted
fix: fix performance issue
fix performance issue by refactoring methods selectRangeOnly and selectRange, using different techniques for obtaining the backend objects depending on the requested range
1 parent 8537114 commit b2acf69

File tree

1 file changed

+88
-23
lines changed
  • selection-grid-flow/src/main/java/com/vaadin/componentfactory/selectiongrid

1 file changed

+88
-23
lines changed

selection-grid-flow/src/main/java/com/vaadin/componentfactory/selectiongrid/SelectionGrid.java

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
@JsModule("./src/vcf-selection-grid.js")
4646
@JsModule("./src/selection-grid.js")
4747
public class SelectionGrid<T> extends Grid<T> {
48+
49+
private Integer selectRangeOnlyFromIndex = null;
50+
private Set<T> selectRangeOnlySelection = new HashSet<T>();
4851

4952
/**
5053
* @see Grid#Grid()
@@ -163,18 +166,41 @@ private String getColumnInternalId(Column<T> column) {
163166
private void selectRange(int fromIndex, int toIndex) {
164167
GridSelectionModel<T> model = getSelectionModel();
165168
if (model instanceof GridMultiSelectionModel) {
166-
DataCommunicator<T> dataCommunicator = super.getDataCommunicator();
167-
Method fetchFromProvider;
168-
try {
169-
fetchFromProvider = DataCommunicator.class.getDeclaredMethod("fetchFromProvider", int.class, int.class);
170-
fetchFromProvider.setAccessible(true);
171-
asMultiSelect().select(((Stream<T>) fetchFromProvider.invoke(dataCommunicator, Math.min(fromIndex, toIndex), Math.max(fromIndex,
172-
toIndex) - Math.min(fromIndex, toIndex) + 1)).collect(Collectors.toList()));
173-
} catch (Exception ignored) {
174-
ignored.printStackTrace();
175-
}
169+
this.getUI().ifPresent(ui->ui.beforeClientResponse(this, (ctx)->{
170+
Set<T> newSelectedItems = obtainNewSelectedItems(fromIndex, toIndex);
171+
asMultiSelect().select(newSelectedItems);
172+
}));
176173
}
177174
}
175+
176+
@SuppressWarnings("unchecked")
177+
private Set<T> obtainNewSelectedItems(int fromIndex, int toIndex) {
178+
DataCommunicator<T> dataCommunicator = super.getDataCommunicator();
179+
Set<T> newSelectedItems = new HashSet<>();
180+
int from = Math.min(fromIndex, toIndex);
181+
int to = Math.max(fromIndex, toIndex) + 1;
182+
int pageSize = dataCommunicator.getPageSize();
183+
if (to - from < (pageSize * 2) - 3) {
184+
// if the range to be retrieved is smaller than 2 pages
185+
// ask the dataCommunicator to retrieve the items so the cache is used
186+
for(int i = from; i < to; i++) {
187+
newSelectedItems.add(dataCommunicator.getItem(i));
188+
}
189+
} else {
190+
// if the range to be retrieved is bigger then use the fetchFromProvider method
191+
// that load the items in pages reducing the amount of queries to the backend
192+
Method fetchFromProvider;
193+
try {
194+
fetchFromProvider = DataCommunicator.class.getDeclaredMethod("fetchFromProvider", int.class, int.class);
195+
fetchFromProvider.setAccessible(true);
196+
newSelectedItems.addAll(((Stream<T>) fetchFromProvider.invoke(dataCommunicator, from, to - from + 1)).collect(Collectors.toList()));
197+
} catch (Exception ignored) {
198+
ignored.printStackTrace();
199+
}
200+
}
201+
return newSelectedItems;
202+
}
203+
178204

179205
/**
180206
* Select the range and deselect the other items
@@ -183,19 +209,58 @@ private void selectRange(int fromIndex, int toIndex) {
183209
* @param toIndex
184210
*/
185211
@ClientCallable
186-
private void selectRangeOnly(int fromIndex, int toIndex) {
187-
GridSelectionModel<T> model = getSelectionModel();
188-
if (model instanceof GridMultiSelectionModel) {
189-
int from = Math.min(fromIndex, toIndex);
190-
int to = Math.max(fromIndex, toIndex);
191-
fetchFromProvider(from, to - from + 1).ifPresent(stream -> {
192-
Set<T> newSelectedItems = stream.collect(Collectors.toSet());
193-
HashSet<T> oldSelectedItems = new HashSet<>(getSelectedItems());
194-
oldSelectedItems.removeAll(newSelectedItems);
195-
asMultiSelect().updateSelection(newSelectedItems, oldSelectedItems);
196-
});
197-
}
198-
}
212+
private void selectRangeOnly(int fromIndex, int toIndex) {
213+
int start = fromIndex < toIndex ? fromIndex : toIndex;
214+
int end = fromIndex < toIndex ? toIndex : fromIndex;
215+
GridSelectionModel<T> model = getSelectionModel();
216+
if (model instanceof GridMultiSelectionModel) {
217+
218+
Set<T> newSelectedItems = new HashSet<T>();
219+
220+
int calculatedFromIndex = start;
221+
222+
// selectRangeOnlySelection will keep the items already selected so there's no unnecessary
223+
// call to backend done
224+
if (!selectRangeOnlySelection.isEmpty()) {
225+
int firstKey = selectRangeOnlyFromIndex;
226+
int lastKey = firstKey + selectRangeOnlySelection.size() - 1;
227+
228+
// recalculate from index so already selected items are not re-selected and no
229+
// unnecessary call to backend is done
230+
if (start == firstKey && end > lastKey) {
231+
calculatedFromIndex = lastKey;
232+
newSelectedItems.addAll(selectRangeOnlySelection);
233+
}
234+
}
235+
236+
final int calculatedFromIndexFinal = calculatedFromIndex;
237+
this.getUI().ifPresent(ui->ui.beforeClientResponse(this, (ctx)->{
238+
newSelectedItems.addAll(obtainNewSelectedItems(calculatedFromIndexFinal, end));
239+
HashSet<T> oldSelectedItems = new HashSet<>(getSelectedItems());
240+
oldSelectedItems.removeAll(newSelectedItems);
241+
asMultiSelect().updateSelection(newSelectedItems, oldSelectedItems);
242+
}));
243+
244+
// update selectRangeOnlySelection with new selected items
245+
selectRangeOnlySelection = new HashSet<T>(getSelectedItems());
246+
selectRangeOnlyFromIndex = fromIndex;
247+
}
248+
}
249+
250+
/**
251+
* Select the range on click and makes sure selectRangeOnlySelection is cleared.
252+
*
253+
* @param fromIndex
254+
* @param toIndex
255+
*/
256+
@ClientCallable
257+
private void selectRangeOnlyOnClick(int fromIndex, int toIndex) {
258+
selectRangeOnlySelection.clear();
259+
selectRangeOnlyFromIndex = null;
260+
this.getUI().ifPresent(ui->ui.beforeClientResponse(this, (ctx)->{
261+
this.selectRangeOnly(fromIndex, toIndex);
262+
}));
263+
}
199264

200265
private Optional<Stream<T>> fetchFromProvider(int offset, int limit) {
201266
DataCommunicator<T> dataCommunicator = super.getDataCommunicator();

0 commit comments

Comments
 (0)