首页 > 解决方案 > Flutter FutureBuilder 快照为空,但 Future 确实返回数据

问题描述

在使用 Flutter 为 Kanboard 开发新的应用程序客户端时,我遇到了以下问题。我有一个 FutureBuilder 应该返回一个带有项目的选择下拉菜单,但是由于某种原因,快照数据为空,尽管 Future 方法确实解析并返回了数据。

完整 page.dart 代码在这里:https ://pastebin.com/J48nxsdZ

有问题的块如下:

Widget _columnSelect() {
return FutureBuilder(
  future: columnProvider.getColumns(task.projectId),
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    List<DropdownMenuItem<String>> columnList = [];
    if (snapshot.hasData) {
      columnList.add(DropdownMenuItem<String>(
          child: Text('Select Column'), value: 0.toString()));
      _columns = snapshot.data;
    } else {
      columnList.add(DropdownMenuItem<String>(
          child: Text('Loading..'), value: 0.toString()));
    }
    _columns.forEach((column) {
      columnList.add(DropdownMenuItem<String>(
          child: Container(
            child: Text(
              column.title,
            ),
          ),
          value: column.id.toString()));
    });
    return Container(
      // margin: EdgeInsets.only(left: 40.0),
      padding: EdgeInsets.symmetric(horizontal: 20.0),
      child: DropdownButtonFormField(
        icon: Padding(
          padding: const EdgeInsets.only(right: 12),
          child: Icon(Icons.view_column, color: Colors.blue),
        ),
        items: columnList,
        value: _columnId,
        decoration: InputDecoration(helperText: 'Optional'),
        onChanged: (newValue) {
          _columnId = newValue;
        },
      ),
    );
  },
);
}

这是用户下拉选择的相同形式的小部件的副本。原始小部件(在同一页面中)如下:

Widget _ownerSelect() {
return FutureBuilder(
  future: userProvider.getUsers(),
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    List<DropdownMenuItem<String>> usernameList = [];
    if (snapshot.hasData) {
      usernameList.add(DropdownMenuItem<String>(
          child: Text('Select Owner'), value: 0.toString()));
      _users = snapshot.data;
    } else {
      usernameList.add(DropdownMenuItem<String>(
          child: Text('Loading..'), value: 0.toString()));
    }
    _users.forEach((user) {
      usernameList.add(DropdownMenuItem<String>(
          child: Container(
            child: Text(
              user.name,
            ),
          ),
          value: user.id.toString()));
    });
    return Container(
      // margin: EdgeInsets.only(left: 40.0),
      padding: EdgeInsets.symmetric(horizontal: 20.0),
      child: DropdownButtonFormField(
        icon: Padding(
          padding: const EdgeInsets.only(right: 12),
          child: Icon(Icons.person, color: Colors.blue),
        ),
        items: usernameList,
        value: _ownerId,
        decoration: InputDecoration(helperText: 'Optional'),
        onChanged: (newValue) {
          _ownerId = newValue;
        },
      ),
    );
  },
);
}

出于某种原因,“_columnSelect”AsyncSnapshot 始终为 null,即使 Future 方法工作正常:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:kanboard/src/models/column_model.dart';
import 'package:kanboard/src/preferences/user_preferences.dart';

class ColumnProvider {
  final _prefs = new UserPreferences();

  Future<List<ColumnModel>> getColumns(projectId) async {
    final Map<String, dynamic> parameters = {
      "jsonrpc": "2.0",
      "method": "getColumns",
      "id": 887036325,
      "params": {"project_id": projectId}
    };

    final credentials = "${_prefs.username}:${_prefs.password}";

    Codec<String, String> stringToBase64 = utf8.fuse(base64);

    String encoded = stringToBase64.encode(credentials);

    final resp = await http.post(
      Uri.parse(_prefs.endpoint),
      headers: <String, String>{"Authorization": "Basic $encoded"},
      body: json.encode(parameters),
    );

    final decodedData = json.decode(utf8.decode(resp.bodyBytes));
    final List<ColumnModel> columns = [];

    final List<dynamic> results = decodedData['result'];

    if (decodedData == null) return [];

    results.forEach((column) {
      final columnTemp = ColumnModel.fromJson(column);
      columns.add(columnTemp);
    });
    print(columns);
    return columns;
  }
}

“print(columns)”的输出返回:

I/flutter ( 9486): [Instance of 'ColumnModel', Instance of 'ColumnModel', Instance of 'ColumnModel', Instance of 'ColumnModel']

我不知道我在这里错过了什么。该表单有 2 个用户下拉选择(使用原始的 FutureBuilder 小部件),效果很好。带有 Future Builder 的 Column 小部件是在 snapshot.data 中存在“空”问题的小部件。

提前感谢您的时间和支持!

标签: flutterdartflutter-futurebuilder

解决方案


我刚刚发现问题出在哪里:

在表单页面(新任务页面)中, columnProvider.getColumns(task.projectId)) 没有执行,因为“task.projectId”参数是一个字符串,但 API 需要一个 int。

我很困惑,因为上一页(包含所有任务的项目页)调用了该方法,而 getColumn 的参数确实是一个整数:int.parse(projectId)。

如果 ID 参数不是 INT 且此特定调用“getColumns”(出于某种原因),Kanboard API 不会返回错误代码。

当然,Flutter(或 Dart)正在等待来自 http.post 的响应,该响应永远不会到达。在比较两个页面中的两个调用时,我注意到了不同之处。

因此,总而言之,我在 getColumn 定义中指定了 int 数据类型参数,以避免任何混淆:

Future<List<ColumnModel>> getColumns(int projectId) async {

此致!


推荐阅读