You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter App构建卡顿:JSON资源加载与Riverpod使用问题

Flutter加载本地JSON数据卡在启动界面的问题修复

我是上月刚接触Flutter的新手,尝试从本地JSON文件加载Item对象并构建列表页面,但手机模拟器一直卡在启动界面,推测可能存在竞态条件或代码逻辑错误。以下是相关代码及修复方案:

原代码片段

列表构建代码

Widget _buildItemList(List<Item> currentItemList) {
return ListView.builder(
    scrollDirection: Axis.vertical,
    shrinkWrap: true,
    itemCount: currentItemList.length,
    itemBuilder: (BuildContext context, int index) {
      return GestureDetector(
          onTap: () {
            Navigator.push(context, MaterialPageRoute(
              builder: (context) {
                return ItemDetailsPage(
                    item: currentItemList[index]);
              },
            ));
          },
          child: Text(currentItemList[index].productName)
      );
    }
);
}

FutureBuilder与数据获取代码

Future<List<Item>> fetchItems() {
    final inventoryService = ref.watch(serviceProvider);
    Future<List<Item>> items = inventoryService.fetchData();  
    return items;
}  

Widget _futureBuilder() {
    return FutureBuilder<List<Item>>(
        future: fetchItems(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            loading = false;
            final result = snapshot.data;
            if (result is Error) {
              const errorMessage = 'Problems getting data';
              return const Center(
                child: Text(
                  errorMessage,
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 18.0),
                ),
              );
            }
            return _buildItemList(result!);
          }
          else {
            return const SliverFillRemaining(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
              );
          }
        }
    );
}

服务层数据加载代码

Future loadItems() async {
var jsonString = await rootBundle.loadString('assets/inventorylist.json');
inventoryResult =
InventoryResult.fromJson(jsonDecode(jsonString));
}

@override
Future<List<Item>> fetchData() async {
    _currentItems = inventoryResultsToItems(inventoryResult) as Future<List<Item>>;
    return _currentItems ?? Future.error('No data found');
}

主函数代码

Future<void> main() async {
  final service = await JsonInventoryService.create(); //runs loadItems()
  runApp(ProviderScope(overrides: [
    serviceProvider.overrideWithValue(service),
  ], child: const MyApp()));
}

问题分析

  1. 类型转换错误:inventoryResultsToItems(inventoryResult)返回的是List<Item>,却被强制转换为Future<List<Item>>,直接触发类型异常,导致数据加载失败。
  2. 错误判断逻辑错误:FutureBuilder中用result is Error判断错误是无效的,正确做法是检查snapshot.hasError。
  3. Future重复执行:FutureBuilder的future参数直接调用fetchItems(),每次页面build都会重新发起请求,导致状态混乱。
  4. 数据加载未等待:若JsonInventoryService.create()中未等待loadItems()完成就返回实例,会导致fetchData()调用时inventoryResult未初始化,返回空错误。
  5. 布局嵌套冲突:_futureBuilder返回SliverFillRemaining,而_buildItemList返回ListView,嵌套滚动组件可能导致布局异常。

修复后的代码

修正服务层逻辑

class JsonInventoryService {
  InventoryResult? inventoryResult;
  List<Item>? _currentItems;

  // 确保JSON加载完成后再返回服务实例
  static Future<JsonInventoryService> create() async {
    final service = JsonInventoryService();
    await service.loadItems();
    return service;
  }

  Future<void> loadItems() async {
    var jsonString = await rootBundle.loadString('assets/inventorylist.json');
    inventoryResult = InventoryResult.fromJson(jsonDecode(jsonString));
  }

  Future<List<Item>> fetchData() async {
    if (inventoryResult == null) {
      return Future.error('库存数据未加载');
    }
    // 移除错误的Future类型转换
    _currentItems = inventoryResultsToItems(inventoryResult!);
    return _currentItems ?? Future.error('未找到数据');
  }
}

修正FutureBuilder逻辑

// 在State类中存储future,避免重复执行
late final Future<List<Item>> _itemsFuture;

@override
void initState() {
  super.initState();
  _itemsFuture = fetchItems();
}

Future<List<Item>> fetchItems() {
  final inventoryService = ref.watch(serviceProvider);
  return inventoryService.fetchData();
}

Widget _futureBuilder() {
  return FutureBuilder<List<Item>>(
    future: _itemsFuture,
    builder: (context, snapshot) {
      // 等待状态显示加载指示器
      if (snapshot.connectionState == ConnectionState.waiting) {
        return const Center(child: CircularProgressIndicator());
      }
      // 错误状态显示错误信息
      else if (snapshot.hasError) {
        return Center(
          child: Text(
            '加载失败: ${snapshot.error}',
            textAlign: TextAlign.center,
            style: const TextStyle(fontSize: 18.0),
          ),
        );
      }
      // 空数据状态提示
      else if (!snapshot.hasData || snapshot.data!.isEmpty) {
        return const Center(
          child: Text(
            '暂无数据',
            style: TextStyle(fontSize: 18.0),
          ),
        );
      }
      // 成功加载显示列表
      else {
        return _buildItemList(snapshot.data!);
      }
    },
  );
}

修正列表布局(避免嵌套滚动)

Widget _buildItemList(List<Item> currentItemList) {
  return ListView.builder(
    scrollDirection: Axis.vertical,
    itemCount: currentItemList.length,
    itemBuilder: (BuildContext context, int index) {
      return GestureDetector(
        onTap: () {
          Navigator.push(context, MaterialPageRoute(
            builder: (context) => ItemDetailsPage(item: currentItemList[index]),
          ));
        },
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
          child: Text(currentItemList[index].productName),
        ),
      );
    },
  );
}

内容的提问来源于stack exchange,提问作者Stooges4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 08:51:07