Skip to content

Commit 6dd441d

Browse files
authored
perf(android): gridlayout with less JNI calls (#10402)
1 parent 7036f12 commit 6dd441d

File tree

8 files changed

+286
-123
lines changed

8 files changed

+286
-123
lines changed

apps/automated/src/ui/layouts/grid-layout-tests.ts

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,31 @@ class RemovalTrackingGridLayout extends GridLayout {
1616
public removedRows = 0;
1717
public removedCols = 0;
1818

19+
// this trick wont work on android anymore as removeRows
20+
// is done in one call and does not go through _onRowRemoved
1921
public _onRowRemoved(itemSpec: ItemSpec, index: number) {
2022
this.removedRows++;
2123
super._onRowRemoved(itemSpec, index);
2224
}
2325

26+
// this trick wont work on android anymore as removeColumns
27+
// is done in one call and does not go through _onColumnRemoved
2428
public _onColumnRemoved(itemSpec: ItemSpec, index: number) {
2529
this.removedCols++;
2630
super._onColumnRemoved(itemSpec, index);
2731
}
32+
public removeRows() {
33+
if (__ANDROID__) {
34+
this.removedRows = this.getRows().length;
35+
}
36+
super.removeRows();
37+
}
38+
public removeColumns() {
39+
if (__ANDROID__) {
40+
this.removedCols = this.getColumns().length;
41+
}
42+
super.removeColumns();
43+
}
2844
}
2945

3046
export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout> {
@@ -39,7 +55,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
3955
public test_item_recycling() {
4056
helper.nativeView_recycling_test(
4157
() => new Button(),
42-
() => new GridLayout()
58+
() => new GridLayout(),
4359
);
4460
}
4561

@@ -350,6 +366,21 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
350366
TKUnit.assertTrue(this.testView.getMeasuredWidth() < platform.Screen.mainScreen.widthPixels);
351367
}
352368

369+
private getGridLayoutRowActualLength(view: GridLayout, index: number) {
370+
if (__ANDROID__) {
371+
return Math.round(layoutHelper.dp(view.nativeViewProtected.getRowActualLength(index)));
372+
} else {
373+
return view.getRows()[index].actualLength;
374+
}
375+
}
376+
private getGridLayoutColumnActualLength(view: GridLayout, index: number) {
377+
if (__ANDROID__) {
378+
return Math.round(layoutHelper.dp(view.nativeViewProtected.getColumnActualLength(index)));
379+
} else {
380+
return view.getColumns()[index].actualLength;
381+
}
382+
}
383+
353384
public test_measuredWidth_when_not_stretched_two_columns() {
354385
this.testView.horizontalAlignment = 'center';
355386
this.testView.addColumn(new ItemSpec(layoutHelper.dp(80), 'pixel'));
@@ -363,9 +394,8 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
363394

364395
this.waitUntilTestElementLayoutIsValid();
365396

366-
var cols = this.testView.getColumns();
367-
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
368-
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
397+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
398+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
369399
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 100, DELTA, 'measured width');
370400
}
371401

@@ -392,9 +422,9 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
392422
this.waitUntilTestElementLayoutIsValid();
393423

394424
var cols = this.testView.getColumns();
395-
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
396-
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
397-
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
425+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
426+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
427+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
398428
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 180, DELTA, 'measured width');
399429
}
400430

@@ -484,7 +514,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
484514
for (var c = 0; c < 4; c++) {
485515
var btn = <layoutHelper.MyButton>this.testView.getChildAt(i++);
486516
if (cols[c].isAbsolute) {
487-
width += layoutHelper.dip(cols[c].actualLength);
517+
width += layoutHelper.dip(this.getGridLayoutColumnActualLength(this.testView, c));
488518
} else {
489519
width += btn.getMeasuredWidth();
490520
}
@@ -495,7 +525,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
495525
maxWidth = Math.max(maxWidth, width);
496526

497527
if (rows[r].isAbsolute) {
498-
maxHeight += layoutHelper.dip(rows[r].actualLength);
528+
maxHeight += layoutHelper.dip(this.getGridLayoutRowActualLength(this.testView, r));
499529
} else {
500530
maxHeight += height;
501531
}
@@ -510,21 +540,19 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
510540
public test_columnsActualWidth_isCorrect() {
511541
this.prepareGridLayout(true);
512542

513-
var cols = this.testView.getColumns();
514-
TKUnit.assertEqual(cols[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
515-
TKUnit.assertEqual(cols[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
516-
TKUnit.assertEqual(cols[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
517-
TKUnit.assertEqual(cols[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
543+
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
544+
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
545+
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
546+
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
518547
}
519548

520549
public test_rowsActualHeight_isCorrect() {
521550
this.prepareGridLayout(true);
522551

523-
var rows = this.testView.getRows();
524-
TKUnit.assertEqual(rows[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
525-
TKUnit.assertEqual(rows[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
526-
TKUnit.assertEqual(rows[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
527-
TKUnit.assertEqual(rows[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
552+
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
553+
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
554+
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
555+
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
528556
}
529557

530558
public test_Measure_and_Layout_Children_withCorrect_size() {
@@ -575,12 +603,10 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
575603

576604
this.waitUntilTestElementLayoutIsValid();
577605

578-
var cols = this.testView.getColumns();
579-
580-
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
581-
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
582-
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
583-
TKUnit.assertAreClose(cols[3].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
606+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
607+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
608+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
609+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
584610
}
585611

586612
public test_margins_and_verticalAlignment_center() {
@@ -799,15 +825,13 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
799825
GridLayout.setRowSpan(btn, 3);
800826
this.waitUntilTestElementLayoutIsValid();
801827

802-
var cols = grid.getColumns();
803-
TKUnit.assertAreClose(cols[0].actualLength, layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
804-
TKUnit.assertAreClose(cols[1].actualLength, layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
805-
TKUnit.assertAreClose(cols[2].actualLength, layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');
828+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 0), layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
829+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
830+
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 2), layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');
806831

807-
var rows = grid.getRows();
808-
TKUnit.assertAreClose(rows[0].actualLength, layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
809-
TKUnit.assertAreClose(rows[1].actualLength, layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
810-
TKUnit.assertAreClose(rows[2].actualLength, layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
832+
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 0), layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
833+
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
834+
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 2), layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
811835
}
812836
}
813837

946 Bytes
Binary file not shown.

packages/core/ui/layouts/grid-layout/grid-layout-common.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,23 @@ function convertGridLength(value: string): ItemSpec {
6363
}
6464
}
6565

66-
function parseAndAddItemSpecs(value: string, func: (itemSpec: ItemSpec) => void): void {
66+
function parseAndAddItemSpecs(value: string) {
6767
// ensure value is a string since view bindings could be parsed as number/int's here
68+
const specs: ItemSpec[] = [];
6869
const arr = `${value}`.split(/[\s,]+/);
6970
for (let i = 0, length = arr.length; i < length; i++) {
7071
const str = arr[i].trim();
7172
if (str.length > 0) {
72-
func(convertGridLength(arr[i].trim()));
73+
specs.push(convertGridLength(arr[i].trim()));
7374
}
7475
}
76+
return specs;
7577
}
7678

7779
export class ItemSpec extends Observable implements ItemSpecDefinition {
7880
private _value: number;
7981
private _unitType: GridUnitType;
82+
toJSON?: () => any;
8083

8184
constructor(...args) {
8285
super();
@@ -147,8 +150,8 @@ export class ItemSpec extends Observable implements ItemSpecDefinition {
147150

148151
@CSSType('GridLayout')
149152
export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
150-
private _rows: Array<ItemSpec> = new Array<ItemSpec>();
151-
private _cols: Array<ItemSpec> = new Array<ItemSpec>();
153+
protected _rows: Array<ItemSpec> = new Array<ItemSpec>();
154+
protected _cols: Array<ItemSpec> = new Array<ItemSpec>();
152155

153156
public static getColumn(element: View): number {
154157
return validateArgs(element).col;
@@ -182,22 +185,48 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
182185
validateArgs(element).rowSpan = value;
183186
}
184187

185-
public addRow(itemSpec: ItemSpec) {
188+
public _addRow(itemSpec: ItemSpec) {
186189
validateItemSpec(itemSpec);
187190
itemSpec.owner = this;
188191
this._rows.push(itemSpec);
192+
}
193+
194+
public addRow(itemSpec: ItemSpec) {
195+
this._addRow(itemSpec);
189196
this._onRowAdded(itemSpec);
190197
this.invalidate();
191198
}
192199

193-
public addColumn(itemSpec: ItemSpec) {
200+
public addRows(itemSpecs: ItemSpec[]) {
201+
for (let index = 0; index < itemSpecs.length; index++) {
202+
const itemSpec = itemSpecs[index];
203+
this._addRow(itemSpec);
204+
this._onRowAdded(itemSpec);
205+
}
206+
this.invalidate();
207+
}
208+
209+
public _addColumn(itemSpec: ItemSpec) {
194210
validateItemSpec(itemSpec);
195211
itemSpec.owner = this;
196212
this._cols.push(itemSpec);
213+
}
214+
215+
public addColumn(itemSpec: ItemSpec) {
216+
this._addColumn(itemSpec);
197217
this._onColumnAdded(itemSpec);
198218
this.invalidate();
199219
}
200220

221+
public addColumns(itemSpecs: ItemSpec[]) {
222+
for (let index = 0; index < itemSpecs.length; index++) {
223+
const itemSpec = itemSpecs[index];
224+
this._addColumn(itemSpec);
225+
this._onColumnAdded(itemSpec);
226+
}
227+
this.invalidate();
228+
}
229+
201230
public addChildAtCell(view: View, row: number, column: number, rowSpan?: number, columnSpan?: number): void {
202231
this.addChild(view);
203232
GridLayoutBase.setRow(view, row);
@@ -316,12 +345,14 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
316345

317346
set rows(value: string) {
318347
this.removeRows();
319-
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addRow(spec));
348+
const specs = parseAndAddItemSpecs(value);
349+
this.addRows(specs);
320350
}
321351

322352
set columns(value: string) {
323353
this.removeColumns();
324-
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addColumn(spec));
354+
const specs = parseAndAddItemSpecs(value);
355+
this.addColumns(specs);
325356
}
326357
}
327358

0 commit comments

Comments
 (0)