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

Flutter登录页跳转首页出现LateInitializationError问题求助

问题:Flutter页面跳转触发LateInitializationError

从登录页面跳转到首页时,出现以下错误:

═════════════ Exception caught by widgets library ═════════════

The following LateError was thrown building HomePage(dirty, dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#d5a11]], state: _HomePageState#10e51):

LateInitializationError: Field 'items' has not been initialized.

The relevant error-causing widget was
HomePage
lib\main.dart:22
When the exception was thrown, this was the stack

#0      CatalogModel.items (package:flutter_catalog/models/catalog.dart)
package:flutter_catalog/models/catalog.dart:1
#1      _HomePageState.build and so on.....

相关代码

catalog.dart

class CatalogModel {
   static late List<Item> items;

  // Get Item by ID
  Item getById(int id) =>
      items.firstWhere((element) => element.id == id, orElse: null);

  // Get Item by position
  Item getByPosition(int pos) => items[pos];
}

class Item {
  final int id;
  final String name;
  final String desc;
  final num price;
  int quantity;
  final String color;
  final String image;

  num get totalPrice => price * quantity;

  Item({
    required this.id,
    required this.name,
    required this.desc,
    required this.price,
    required this.color,
    required this.image,
    this.quantity = 1,
  });

  Item copyWith({
    int? id,
    String? name,
    String? desc,
    num? price,
    String? color,
    int? quantity = 1,
    String? image,
  }) {
    return Item(
      id: id ?? this.id,
      name: name ?? this.name,
      desc: desc ?? this.desc,
      price: price ?? this.price,
      color: color ?? this.color,
      image: image ?? this.image,
      quantity: quantity ?? this.quantity,
    );
}

HomePage.dart

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  @override
  void initState() {
    super.initState();
    loadData();
  }

  loadData() async {
    await Future.delayed(Duration(seconds: 2));
    final catalogJson = 
        await rootBundle.loadString("assets/files/catalog.json");
    final decodedData = jsonDecode(catalogJson);
    var productsData = decodedData["products"];
    CatalogModel.items = List.from(productsData)
        .map<Item>((item) => Item.fromMap(item))
        .toList();
    (VxState.store as MyStore).items = CatalogModel.items;
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    final _cart = (VxState.store as MyStore).cart;
    final MyStore store = VxState.store;
    return Scaffold(
        backgroundColor: context.canvasColor,
        floatingActionButton: VxBuilder(
          mutations: {AddMutation, RemoveMutation},
          builder: (ctx,_,status) =>FloatingActionButton(
          onPressed: () =>
              store.navigator.routeManager.push(Uri.parse(MyRoutes.cartRoute)),
          backgroundColor: context.theme.buttonColor,
          child: Icon(
            CupertinoIcons.cart,
            color: Colors.white,
          ),
        ).badge(
              color: Vx.red500,
              size: 22,
              count: _cart.items.length,
              textStyle: TextStyle(
                color: Colors.black,
                fontWeight: FontWeight.bold,
              )),
        ),
        body: SafeArea(
          child: Container(
            padding: Vx.m32,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                CatalogHeader(),
                CupertinoSearchTextField(
                  onChanged: (value) {
                    SearchMutation(value);
                  },
                ).py12(),
                if (CatalogModel.items !=null && CatalogModel.items.isNotEmpty)
                  CatalogList().py16().expand()
                else
                  CircularProgressIndicator().centered().expand(),
              ],
            ),
          ),
        ));

}
}

Cart.dart

class CartModel {
  late CatalogModel _catalog;

  final List<int> _itemIds = [];
  CatalogModel get catalog => _catalog;

  set catalog(CatalogModel newCatalog) {
    assert(newCatalog != null);
    _catalog = newCatalog;
  }
  List<Item> get items => _itemIds.map((id) => _catalog.getById(id)).toList();
  num get totalPrice =>
      items.fold(0, (total, current) => total + current.price);


}

class AddMutation extends VxMutation<MyStore> {
  final Item item;

  AddMutation(this.item); 
 @override
  perform() {
    store!.cart._itemIds.add(item.id);
    
  }
}
 
 class RemoveMutation extends VxMutation<MyStore> {
  final Item item;

  RemoveMutation(this.item); 
 @override
  perform() {
    store!.cart._itemIds.remove(item.id);
    
  }
}

解决方案

核心问题是**late修饰的静态变量items在异步初始化完成前被访问**,late变量未初始化时直接访问会触发LateInitializationError,而非返回null,导致build方法中的null判断失效。

1. 修改CatalogModel的items定义

将late改为可空类型,避免未初始化时访问报错:

class CatalogModel {
  // 改为可空列表,初始值为null
  static List<Item>? items;

  // 修改getById,处理items为null的情况,返回可空Item
  Item? getById(int id) => items?.firstWhere((element) => element.id == id, orElse: () => null);

  // 修改getByPosition,增加空判断和索引有效性检查
  Item? getByPosition(int pos) {
    if (items == null || pos >= items!.length) return null;
    return items![pos];
  }
}

2. 修复CartModel的catalog初始化问题

将late CatalogModel改为可空类型,并在getter中增加空判断,避免访问未初始化的catalog:

class CartModel {
  CatalogModel? _catalog;

  final List<int> _itemIds = [];
  CatalogModel? get catalog => _catalog;

  set catalog(CatalogModel newCatalog) {
    _catalog = newCatalog;
  }

  // 修改items getter,过滤null值
  List<Item> get items {
    if (_catalog == null || _catalog!.items == null) return [];
    return _itemIds.map((id) => _catalog!.getById(id)).whereType<Item>().toList();
  }

  num get totalPrice =>
      items.fold(0, (total, current) => total + current.price);
}

3. 确保HomePage的逻辑兼容可空类型

原HomePage中的if (CatalogModel.items !=null && CatalogModel.items.isNotEmpty)判断已经兼容可空类型,无需修改。但要注意在CatalogList组件中,使用CatalogModel.items时要确保它不为null(因为判断已经过滤了null和空的情况)。

4. 保留required关键字

required是构造函数必填参数的修饰符,不能随意移除,否则会导致Item构造函数参数缺失的错误,保持原代码中的required即可。

完成以上修改后,从登录页跳转到首页时,build方法会先显示CircularProgressIndicator,直到loadData异步完成并初始化CatalogModel.items,之后自动切换显示CatalogList,不会再触发LateInitializationError。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:05:27