Thanks to visit codestin.com
Credit goes to github.com

Skip to content

perf(android): gridlayout with less JNI calls #10402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 1, 2024
90 changes: 57 additions & 33 deletions apps/automated/src/ui/layouts/grid-layout-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,31 @@ class RemovalTrackingGridLayout extends GridLayout {
public removedRows = 0;
public removedCols = 0;

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

// this trick wont work on android anymore as removeColumns
// is done in one call and does not go through _onColumnRemoved
public _onColumnRemoved(itemSpec: ItemSpec, index: number) {
this.removedCols++;
super._onColumnRemoved(itemSpec, index);
}
public removeRows() {
if (__ANDROID__) {
this.removedRows = this.getRows().length;
}
super.removeRows();
}
public removeColumns() {
if (__ANDROID__) {
this.removedCols = this.getColumns().length;
}
super.removeColumns();
}
}

export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout> {
Expand All @@ -39,7 +55,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
public test_item_recycling() {
helper.nativeView_recycling_test(
() => new Button(),
() => new GridLayout()
() => new GridLayout(),
);
}

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

private getGridLayoutRowActualLength(view: GridLayout, index: number) {
if (__ANDROID__) {
return Math.round(layoutHelper.dp(view.nativeViewProtected.getRowActualLength(index)));
} else {
return view.getRows()[index].actualLength;
}
}
private getGridLayoutColumnActualLength(view: GridLayout, index: number) {
if (__ANDROID__) {
return Math.round(layoutHelper.dp(view.nativeViewProtected.getColumnActualLength(index)));
} else {
return view.getColumns()[index].actualLength;
}
}

public test_measuredWidth_when_not_stretched_two_columns() {
this.testView.horizontalAlignment = 'center';
this.testView.addColumn(new ItemSpec(layoutHelper.dp(80), 'pixel'));
Expand All @@ -363,9 +394,8 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>

this.waitUntilTestElementLayoutIsValid();

var cols = this.testView.getColumns();
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 100, DELTA, 'measured width');
}

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

var cols = this.testView.getColumns();
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 180, DELTA, 'measured width');
}

Expand Down Expand Up @@ -484,7 +514,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
for (var c = 0; c < 4; c++) {
var btn = <layoutHelper.MyButton>this.testView.getChildAt(i++);
if (cols[c].isAbsolute) {
width += layoutHelper.dip(cols[c].actualLength);
width += layoutHelper.dip(this.getGridLayoutColumnActualLength(this.testView, c));
} else {
width += btn.getMeasuredWidth();
}
Expand All @@ -495,7 +525,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
maxWidth = Math.max(maxWidth, width);

if (rows[r].isAbsolute) {
maxHeight += layoutHelper.dip(rows[r].actualLength);
maxHeight += layoutHelper.dip(this.getGridLayoutRowActualLength(this.testView, r));
} else {
maxHeight += height;
}
Expand All @@ -510,21 +540,19 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
public test_columnsActualWidth_isCorrect() {
this.prepareGridLayout(true);

var cols = this.testView.getColumns();
TKUnit.assertEqual(cols[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
TKUnit.assertEqual(cols[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
TKUnit.assertEqual(cols[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
TKUnit.assertEqual(cols[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
}

public test_rowsActualHeight_isCorrect() {
this.prepareGridLayout(true);

var rows = this.testView.getRows();
TKUnit.assertEqual(rows[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
TKUnit.assertEqual(rows[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
TKUnit.assertEqual(rows[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
TKUnit.assertEqual(rows[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
}

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

this.waitUntilTestElementLayoutIsValid();

var cols = this.testView.getColumns();

TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
TKUnit.assertAreClose(cols[3].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
}

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

var cols = grid.getColumns();
TKUnit.assertAreClose(cols[0].actualLength, layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
TKUnit.assertAreClose(cols[1].actualLength, layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
TKUnit.assertAreClose(cols[2].actualLength, layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 0), layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 2), layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');

var rows = grid.getRows();
TKUnit.assertAreClose(rows[0].actualLength, layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
TKUnit.assertAreClose(rows[1].actualLength, layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
TKUnit.assertAreClose(rows[2].actualLength, layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 0), layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 2), layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
}
}

Expand Down
Binary file modified packages/core/platforms/android/widgets-release.aar
Binary file not shown.
47 changes: 39 additions & 8 deletions packages/core/ui/layouts/grid-layout/grid-layout-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,23 @@ function convertGridLength(value: string): ItemSpec {
}
}

function parseAndAddItemSpecs(value: string, func: (itemSpec: ItemSpec) => void): void {
function parseAndAddItemSpecs(value: string) {
// ensure value is a string since view bindings could be parsed as number/int's here
const specs: ItemSpec[] = [];
const arr = `${value}`.split(/[\s,]+/);
for (let i = 0, length = arr.length; i < length; i++) {
const str = arr[i].trim();
if (str.length > 0) {
func(convertGridLength(arr[i].trim()));
specs.push(convertGridLength(arr[i].trim()));
}
}
return specs;
}

export class ItemSpec extends Observable implements ItemSpecDefinition {
private _value: number;
private _unitType: GridUnitType;
toJSON?: () => any;

constructor(...args) {
super();
Expand Down Expand Up @@ -147,8 +150,8 @@ export class ItemSpec extends Observable implements ItemSpecDefinition {

@CSSType('GridLayout')
export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
private _rows: Array<ItemSpec> = new Array<ItemSpec>();
private _cols: Array<ItemSpec> = new Array<ItemSpec>();
protected _rows: Array<ItemSpec> = new Array<ItemSpec>();
protected _cols: Array<ItemSpec> = new Array<ItemSpec>();

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

public addRow(itemSpec: ItemSpec) {
public _addRow(itemSpec: ItemSpec) {
validateItemSpec(itemSpec);
itemSpec.owner = this;
this._rows.push(itemSpec);
}

public addRow(itemSpec: ItemSpec) {
this._addRow(itemSpec);
this._onRowAdded(itemSpec);
this.invalidate();
}

public addColumn(itemSpec: ItemSpec) {
public addRows(itemSpecs: ItemSpec[]) {
for (let index = 0; index < itemSpecs.length; index++) {
const itemSpec = itemSpecs[index];
this._addRow(itemSpec);
this._onRowAdded(itemSpec);
}
this.invalidate();
}

public _addColumn(itemSpec: ItemSpec) {
validateItemSpec(itemSpec);
itemSpec.owner = this;
this._cols.push(itemSpec);
}

public addColumn(itemSpec: ItemSpec) {
this._addColumn(itemSpec);
this._onColumnAdded(itemSpec);
this.invalidate();
}

public addColumns(itemSpecs: ItemSpec[]) {
for (let index = 0; index < itemSpecs.length; index++) {
const itemSpec = itemSpecs[index];
this._addColumn(itemSpec);
this._onColumnAdded(itemSpec);
}
this.invalidate();
}

public addChildAtCell(view: View, row: number, column: number, rowSpan?: number, columnSpan?: number): void {
this.addChild(view);
GridLayoutBase.setRow(view, row);
Expand Down Expand Up @@ -316,12 +345,14 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {

set rows(value: string) {
this.removeRows();
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addRow(spec));
const specs = parseAndAddItemSpecs(value);
this.addRows(specs);
}

set columns(value: string) {
this.removeColumns();
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addColumn(spec));
const specs = parseAndAddItemSpecs(value);
this.addColumns(specs);
}
}

Expand Down
Loading
Loading