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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:20:27