Flutter:有没有一种方法可以异步构建复杂的小部件而不阻塞主隔离?

时间:2020-06-14 07:40:23

标签: flutter dart async-await

我想显示一个DataTable,其中数据输入根据用户的输入而变化(用户可以选择一个csv文件,然后其内容将显示在DataTable小部件中)。

我的问题是,根据用户的csv文件中的行和列数,创建DataTable可能需要花费几秒钟的时间,并且屏幕同时冻结,这显然是不好的用户体验。因此,我的想法是在单独的隔离区中创建DataTable,等待结果(请参见下面的代码),并在等待结果时显示CircularProgressIndicator。

不幸的是,这种方法不起作用(我认为是因为CustomDataTable不是有效的message type)。

我在这里使用隔离的方法可能是错误的(我是扑朔迷离的新手),如果可以引导我朝正确的方向前进,我很乐意转向另一种策略。

// In the class of my Stateful Widget that will display the CustomDataTable I have this function spawning the isolate and awaiting the CustomDataTable
Future<CustomDataTable> createCustomTableInIsolate(List<Map<String, String>> data, List<Map<String, String>> selectedRows, List<String> columnNames, Function onSelectedRow) async {
  var map = {
    'data': data,
    'selectedRows': selectedRows,
    'columnNames': columnNames,
    'onSelectedRow': onSelectedRow,
  };

  CustomDataTable dataTable = await compute(createCustomTable, map);
  return dataTable;
}

//... somewhere in my widget tree
FutureBuilder<CustomDataTable>(
    future: createCustomTableInIsolate(),
    builder: (BuildContext ctx,
        AsyncSnapshot snapshot) {
      if (snapshot.connectionState ==
          ConnectionState.waiting) {
        return Center(
              child: CircularProgressIndicator(),
            );
      } else if (!snapshot.hasData) {
        return Center(
              child: Text('Please check your input data...'),
            );
      } else {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: ConstrainedBox(
              constraints: BoxConstraints(
                minWidth: constraints.minWidth,
              ),
              child: snapshot.data),
        );
      }
    },
  ),
// ... 

// Function creating the CustomDataTable in different isolate (outside of stateful widget class)
CustomDataTable createCustomTable(Map<String, dynamic> map) {
  return CustomDataTable(
    data: map['data'],
    selectedRows: map['selectedRows'],
    columnNames: map['columnNames'],
    onSelectedRow: map['onSelectedRow'],
  );
}

// Separate class to create the DataTable widget
class CustomDataTable extends StatelessWidget {
  final List<Map<String, String>> data;
  final List<Map<String, String>> selectedRows;
  final List<String> columnNames;
  final Function onSelectedRow;

  CustomDataTable({
    @required this.data,
    @required this.selectedRows,
    @required this.columnNames,
    @required this.onSelectedRow,
  });

  @override
  Widget build(BuildContext context) {
    return DataTable(
      columns: columnNames.map((columnName) {
        return DataColumn(
          label: Text(
            columnName,
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.w600,
            ),
          ),
        );
      }).toList(),
      rows: data.map((column) {
        var columnValues = column.values;
        return DataRow(
            selected: selectedRows.contains(column),
            onSelectChanged: (selected) {
              onSelectedRow(selected, column);
            },
            cells: columnValues.map((cellValue) {
              return DataCell(
                Text(
                  cellValue,
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
              );
            }).toList());
      }).toList(),
    );
  }
}

0 个答案:

没有答案