Flutter RangeError(index)错误:购物车页面无法显示排查
Flutter EatEasy项目购物车页面显示错误排查
我是编程新手,正在开发EatEasy项目,当前遇到购物车页面无法显示的问题。该页面用于展示用户选择的食材,但Flutter抛出错误RangeError (index): Invalid Value: Only valid value is 0: 1,且错误指向main.dart中的MaterialApp组件。
我参考Udemy教程编写代码,仅做了少量调整,但仍出现错误,数据存储在Firebase中。详细错误指向assistantMethod中的var quanNumber = int.parse(listIngredientCharacters[1].toString());代码行,同时ShoppingListScreen的initState调用separateIngredientQuantities()时触发该错误。
main.dart代码
import 'package:eat_easy_project/assistantMethod/shopping_List_Counter.dart'; import 'package:eat_easy_project/global/global.dart'; import 'package:eat_easy_project/splashScreen/splash_screen.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:provider/provider.dart'; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); sharedPreferences = await SharedPreferences.getInstance(); await Firebase.initializeApp(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (c)=> ShoppingListCounter()), ], child: MaterialApp( title: 'EatEasy Project', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, ), home: const MySplashScreen(), ), ); } }
ShoppingListDesign代码
import 'package:eat_easy_project/models/ingredients.dart'; import 'package:flutter/material.dart'; class ShoppingListDesign extends StatefulWidget { final Ingredients? model; BuildContext? context; final List <int>? separateIngredientQuantitiesList; ShoppingListDesign({ this.model, this.context, this.separateIngredientQuantitiesList, }); @override State<ShoppingListDesign> createState() => _ShoppingListDesignState(); } class _ShoppingListDesignState extends State<ShoppingListDesign> { @override Widget build(BuildContext context) { return InkWell( splashColor: Colors.cyan, child: Padding( padding: const EdgeInsets.all(6.0), child: Container( height: 165, width: MediaQuery.of(context).size.width, child: Row( children: [ Image.network(widget.model!.ingredientAvatarUrl!, width: 140, height: 120,), const SizedBox(width: 6,), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.model!.ingredientName!, style: const TextStyle( color: Colors.black, fontSize: 16, fontFamily: "Kiwi", ), ), const SizedBox( height: 1.0, ), Row( children: [ const Text( "x ", style: TextStyle( color: Colors.black, fontSize: 25, fontFamily: "Acme", ), ), Text( widget.separateIngredientQuantitiesList.toString(), style: const TextStyle( color: Colors.black, fontSize: 25, fontFamily: "Acme", ), ), ], ), Row( children: [ const Text( "Price: ", style: TextStyle( fontSize: 15, color: Colors.grey, ), ), const Text( "RM ", style: TextStyle( fontSize: 15, color: Colors.grey, ), ), Text( widget.model!.ingredientPrice.toString(), style: const TextStyle( fontSize: 15, color: Colors.grey, ), ), ], ) ], ), ], ), ), ), ); } }
assistantMethod代码
separateIngredientUIDs() { List<String> separateIngredientUIDsList=[], defaultIngredientList= []; int i=0; defaultIngredientList = sharedPreferences!.getStringList("userShoppingList")!; for(i; i<defaultIngredientList.length; i++) { String ingredient = defaultIngredientList[i].toString(); var pos = ingredient.lastIndexOf(":"); String getIngredientID = (pos != -1) ? ingredient.substring(0, pos) : ingredient; print("\nThis is ingredientID now = " + getIngredientID); separateIngredientUIDsList.add(getIngredientID); } print("\nThis is Ingredients List now = " ); print(separateIngredientUIDsList); return separateIngredientUIDsList; } addIngredientToCart(String? ingredientUID, BuildContext context, int ingredientCounter) { List<String>? tempList = sharedPreferences!.getStringList("userShoppingList"); tempList!.add(ingredientUID! + ":$ingredientCounter"); FirebaseFirestore.instance.collection("user") .doc(firebaseAuth.currentUser!.uid).update({ "userShoppingList": tempList, }).then((value) { Fluttertoast.showToast(msg: "Ingredient Added Successfully."); sharedPreferences!.setStringList("userShoppingList", tempList); //update badge Provider.of<ShoppingListCounter>(context, listen: false).displayShoppingListIngredientNumber(); }); } separateIngredientQuantities() { List<int> separateIngredientQuantityList=[]; List<String> defaultIngredientList=[]; int i=0; defaultIngredientList = sharedPreferences!.getStringList("userShoppingList")!; for(i; i<defaultIngredientList.length; i++) { String ingredient = defaultIngredientList[i].toString(); List<String> listIngredientCharacters = ingredient.split(":").toList(); var quanNumber = int.parse(listIngredientCharacters[1].toString()); print("\nThis is Quantity Number = " + quanNumber.toString()); separateIngredientQuantityList.add(quanNumber); } print("\nThis is Quantity List now = " ); print(separateIngredientQuantityList); return separateIngredientQuantityList; }
ShoppingListScreen代码
class ShoppingListScreen extends StatefulWidget { Ingredients? model; ShoppingListScreen({this.model}); @override State<ShoppingListScreen> createState() => _ShoppingListScreenState(); } class _ShoppingListScreenState extends State<ShoppingListScreen> { @override void initState() { super.initState(); separateIngredientQuantities(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar ( flexibleSpace: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color.fromARGB(255, 192, 234, 240), Color.fromARGB(255, 108, 173, 70), ], begin: FractionalOffset(0.0, 0.0), end: FractionalOffset(1.0, 0.0), stops: [0.0, 1.0], tileMode: TileMode.clamp, ) ), ), title: const Text( "EatEasy", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold,) ), centerTitle: true, automaticallyImplyLeading: true, actions: [ Stack( children: [ IconButton( icon: const Icon(Icons.shopping_cart, color: Colors.cyan,), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (c)=> ShoppingListScreen(model: widget.model,))); }, ), Positioned( child: Stack( children: [ const Icon( Icons.brightness_1, size: 20.0, color: Color.fromARGB(255, 29, 88, 31), ), Positioned( top: 3, right: 4, child: Center( child: Consumer<ShoppingListCounter>( builder: (context, counter, c) { return Text( counter.count.toString(), style: const TextStyle(color: Color.fromARGB(255, 209, 218, 226)), ); } ), ), ), ], ), ), ], ), ], ), floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox(width: 10,), Align( alignment: Alignment.bottomLeft, child: FloatingActionButton.extended( label: const Text("Clear List", style: TextStyle(fontSize: 16),), backgroundColor: Colors.cyan, icon: const Icon(Icons.clear_all), onPressed: () { }, ), ), Align( alignment: Alignment.bottomLeft, child: FloatingActionButton.extended( label: const Text("Calculate Total", style: TextStyle(fontSize: 16),), backgroundColor: Colors.cyan, icon: const Icon(Icons.calculate), onPressed: () { }, ), ) ], ), body: CustomScrollView( slivers: [ //overall total amount SliverPersistentHeader( pinned: true, delegate: TextWidgetHeader(title: "Total Amount = 120"), ), //display cart ingredients with quantity StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection("ingredients") .where("ingredientUID", whereIn: separateIngredientUIDs()) .orderBy("ingredientPrice", descending: true) .snapshots(), builder: (context, snapshot) { return !snapshot.hasData ? SliverToBoxAdapter(child: Center(child: circularProgress()),) : snapshot.data!.docs.length == 0 ? //startBuildingList Container() : SliverList( delegate: SliverChildBuilderDelegate((context, index) { Ingredients model = Ingredients.fromJson( snapshot.data!.docs[index].data()! as Map<String, dynamic>, ); return ShoppingListDesign( model: model, context: context, separateIngredientQuantitiesList: [index] , ); }, //childCount: snapshot.hasData ? snapshot.data!.docs.length : 0, ), ); }, ), ], ), ); } }
错误原因及修复方案
错误RangeError (index): Invalid Value: Only valid value is 0: 1说明在separateIngredientQuantities()方法中,尝试访问listIngredientCharacters[1]时,该列表仅包含一个元素(仅索引0有效)。核心问题是userShoppingList中存在不符合食材UID:数量格式的条目。
- 验证数据格式:检查SharedPreferences中
userShoppingList的每个条目,确保都包含:分隔符,格式严格为食材UID:数量。 - 添加异常处理:修改
separateIngredientQuantities()方法,增加列表长度判断,避免索引越界:List<String> listIngredientCharacters = ingredient.split(":").toList(); if (listIngredientCharacters.length >= 2) { var quanNumber = int.parse(listIngredientCharacters[1].toString()); separateIngredientQuantityList.add(quanNumber); } else { // 处理格式错误的条目,可默认数量为1或跳过该条目 separateIngredientQuantityList.add(1); print("格式错误的食材条目:$ingredient"); } - 规范添加逻辑:确保
addIngredientToCart()方法中添加的条目严格遵循ingredientUID:ingredientCounter格式,避免生成无效数据。 - 初始化空列表:确保
userShoppingList在SharedPreferences中初始化为空列表而非null,防止空指针异常。
内容的提问来源于stack exchange,提问作者raihan wilinio
相关产品推荐
相关产品推荐

