RangeError(索引):无效值:仅有效值为0:1

时间:2020-01-23 06:23:56

标签: flutter

我是新手。我正在尝试将数据列表添加到视图中。数据列表具有不同长度的不同订单项集。我从API获取数据,但是由于订单数据长度不同,因此出现如下图所示的错误。我有如下的json api:

enter image description here

{ 
 "status":"success",
 "message":"Data Fetched",
 "data":{ 
  "list":[ 
     { 
        "id":27,
        "order_code":"7wfelnkhuodlbvdseley1",
        "chef_id":1,
        "user_id":1,
        "order_status":1,
        "status":1,
        "order_datetime":"2020-01-21 18:05:00",
        "user_location_id":1,
        "price":1600,
        "coupon_id":null,
        "use_coupon":0,
        "discount":0,
        "final_price":1600,
        "vat_amt":208,
        "delivery_charge_amt":0,
        "payment_id":1,
        "delivery_time":null,
        "delivery_user_id":null,
        "payment_status":0,
        "payment_price":null,
        "payment_time":null,
        "reject_message":null,
        "created_at":"2020-01-21 18:05:00",
        "updated_at":"2020-01-21 18:07:46",
        "orderdata":[ 
           { 
              "id":30,
              "order_code_id":27,
              "chef_id":1,
              "food_id":17,
              "user_id":1,
              "additional_info":null,
              "food_qty":4,
              "instruction":null,
              "price":400,
              "food":{ 
                 "id":17,
                 "name":"Prawns Chilli",
                 "description":"<p>Seared&nbsp;prawns&nbsp;smothered in a spicy, sticky Asian sauce, 
                  these Asian&nbsp;Chilli&nbsp;Garlic&nbsp;Prawns&nbsp;will have you smacking your 
                  lips in utter satisfaction, feeling like you&rsquo;ve just dined at a fancy modern 
                  Thai restaurant.<wbr />&nbsp;</p>",
                 "ingredient_detail":null,
                 "price":500,
                 "discount_price":400,
                 "ribbon_text":null,
                 "image":"1576657695-prawn chilli3.jpg",
                 "banner_image":null,
                 "published_date":"2019-12-18",
                 "is_offer":1
              }
           }
        ]
     },
     { 
        "id":29,
        "order_code":"lzquyrmthdahxmjm81ja1",
        "chef_id":1,
        "user_id":1,
        "order_status":1,
        "status":1,
        "order_datetime":"2020-01-21 19:17:52",
        "user_location_id":1,
        "price":280,
        "coupon_id":null,
        "use_coupon":0,
        "discount":0,
        "final_price":280,
        "vat_amt":36.4,
        "delivery_charge_amt":50,
        "payment_id":1,
        "delivery_time":null,
        "delivery_user_id":null,
        "payment_status":0,
        "payment_price":null,
        "payment_time":null,
        "reject_message":null,
        "created_at":"2020-01-21 19:17:52",
        "updated_at":"2020-01-21 19:18:30",
        "orderdata":[ 
           { 
              "id":33,
              "order_code_id":29,
              "chef_id":1,
              "food_id":11,
              "user_id":1,
              "additional_info":null,
              "food_qty":2,
              "instruction":null,
              "price":250,
              "food":{ 
                 "id":11,
                 "name":"Chicken burger",
                 "description":"<p>The juicyness of the meat will make you feel heaven.</p>",
                 "ingredient_detail":null,
                 "price":300,
                 "discount_price":250,
                 "ribbon_text":null,
                 "image":"1576654603-chick burger.jpg",
                 "banner_image":null,
                 "published_date":"2019-12-18",
                 "is_offer":1
              }
           },
           { 
              "id":34,
              "order_code_id":29,
              "chef_id":1,
              "food_id":4,
              "user_id":1,
              "additional_info":null,
              "food_qty":2,
              "instruction":null,
              "price":140,
              "food":{ 
                 "id":4,
                 "name":"Momo",
                 "description":"<p>This juicy steamed momos are prepared from the ground water buffalo meat and are called \"Buff&nbsp;momo\". The wrappers are very thinly rolled and the filling is deliciously spicy and juicy, served along with tangy yellow chutney and classic spicy tomato sauce that compliments the&nbsp;taste&nbsp;of steamed momos.</p>",
                 "ingredient_detail":"<p>Tomato, Ground meat ,Flour, Chilli pepper, Garlic, Ginger, Scallion, Black pepper and Soy sauce</p>",
                 "price":150,
                 "discount_price":140,
                 "ribbon_text":null,
                 "image":"1576651666-momo.jpg",
                 "banner_image":null,
                 "published_date":"2019-11-18",
                 "is_offer":1
              }
           }
        ]
     }
  ]
}
}

我的完整小部件代码:

    class OnProcessPage extends StatefulWidget {
         @override
         State<StatefulWidget> createState() {
          return _OnProcessTile();
        }
    }

      class _OnProcessTile extends State<OnProcessPage> {
      bool _isLoading = false;
      List<ListD> foodData = [];
      List<Orderdata> orderData = [];
      SharedPreferences sharedPreferences;

      @override
      void initState() {
        super.initState();
        setState(() {
          _isLoading = true;
        });
        getPrefs();
        getOnProcessRequest();
      }
@override
  Widget build(BuildContext context) {
    return Center(
        child: Stack(
      children: <Widget>[
        Opacity(
          opacity: _isLoading
              ? 0.3
              : 1, // You can reduce this when loading to give different effect
          child: AbsorbPointer(
            absorbing: _isLoading,
            child: _buildCardList(context),
          ),
        ),
        Opacity(
            opacity: _isLoading ? 1.0 : 0,
            child: Center(
              child: CircularProgressIndicator(
                backgroundColor: Theme.of(context).primaryColor,
              ),
            )),
      ],
    ));

  }

  Widget _buildCardList(BuildContext context) {
    return ListView.builder(
        itemCount: foodData == null ? 0 : foodData.length,
        itemBuilder: (context, int index) {
          return Wrap(
            children: <Widget>[
              Container(
                  margin: EdgeInsets.only(bottom: 10),
                  child: Card(
                      child: Column(
                    children: <Widget>[
                       _buildCardView(context, index),
                      _cardBottomView(context, index)
                    ],
                  )))
            ],
          );
        });
  }

  Widget _buildCardView(BuildContext context, int index) {
    return Wrap(
      children: <Widget>[
        Container(
          child: Container(
            margin: EdgeInsets.all(10.0),
            child: Column(
              children: <Widget>[
                _cardTopSection(context, index),
                _cardMiddleSection(context, index),
                _cardTotalPrice(context, index),
                Container(
                  height: 1,
                  color: Color.fromRGBO(232, 232, 232, 1),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
  Widget _cardTotalPrice(BuildContext context, int i) {
    return Container(
      margin: EdgeInsets.only(bottom: 5.0),
      child: Padding(
        padding: EdgeInsets.only(top: 3, bottom: 3),
        child: Row(
          children: <Widget>[
            Expanded(
              child: Text(""),
            ),
            Expanded(
              child: Text("Total",
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 18,
                  )),
            ),
            Expanded(
              child: Text(
                "${foodData[i].finalPrice}",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 18,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
  Widget _cardTopSection(BuildContext context, int index) {
    return Container(
      color: Color.fromRGBO(232, 232, 232, 1),
      child: Row(
        children: <Widget>[
          _topLeftSection(index),
          _topmiddleSection(index),
          _toprightSection(index)
        ],
      ),
    );
  }

  Widget _cardMiddleSection(BuildContext context, int i) {
    return Container(
      margin: EdgeInsets.only(top: 10.0),
      child: ListView.builder(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemCount:
              foodData[i].orderdata == null ? 0 : foodData[i].orderdata.length,
          itemBuilder: (context, i) {
            print("Item Builder");
            print(i);
            print("Item Builder");
            return _cardMiddleItems(i);
          }),
    );
  }

  Widget _cardMiddleItems(int i) {
    print("Middle");
    print(i);
    print("Middle");

    return Container(
      margin: EdgeInsets.only(bottom: 5.0),
      child: Padding(
        padding: EdgeInsets.only(top: 3, bottom: 3),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Expanded(
              child: Text("${orderData[i].food.name}"),
            ),
            Expanded(
              child: Text("${orderData[i].foodQty}"),
            ),
            Expanded(
              child: Text("${orderData[i].price}"),
            ),
          ],
        ),
      ),
    );
  }

  Widget _topLeftSection(int index) {
    return Container(
      child: CircleAvatar(
        backgroundImage: AssetImage('assets/images/momo.jpg'),
        backgroundColor: Colors.lightGreen,
        radius: 24.0,
      ),
    );
  }

  Widget _topmiddleSection(int i) {
    return Expanded(
      child: Container(
        child: Column(
          children: <Widget>[
            Text("Coldplay "),
            Text("${foodData[i].createdAt}")
            // new Text("Hi whatsup?"),
          ],
        ),
      ),
    );
  }

  Widget _toprightSection(int index) {
    return Expanded(
      child: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            Text(
              "#" + "${foodData[index].id}",
              style: TextStyle(color: Colors.black, fontSize: 18.0),
            ),
          ],
        ),
      ),
    );
  }

  Widget _cardBottomView(BuildContext context, int index) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        Text(
          "Order Status",
          style: TextStyle(fontSize: 18),
        ),
        RaisedButton(
          onPressed: () => {},
          color: Colors.green,
          child: Text(
            "Cooking",
            style: TextStyle(color: Colors.white),
          ),
        ),
        RaisedButton(
          onPressed: () => {
            sharedPreferences.setBool('process', true),
            sharedPreferences.setBool('new', false),
            Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (BuildContext context) => RequestDetails(),
                  settings: RouteSettings(
                    arguments: foodData[index],
                  ),
                ))
          },
          color: Theme.of(context).primaryColor,
          child: Text("Details", style: TextStyle(color: Colors.white)),
        ),
      ],
    );
  }

  Future<NewRequestResponse> getOnProcessRequest() async {
    print("OnProcess");
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    String token = sharedPreferences.getString("api_token");
    Map<String, String> headers = {"Authorization": token};
    var jsonResponse;
    NewRequestResponse newRequestResponse;
    var response = await http.post(
        "url",
        headers: headers);
    if (response.statusCode == 200) {
      print("Onprocess Inside 200");
      jsonResponse = json.decode(response.body);
      print(jsonResponse);
      if (jsonResponse != null) {
        newRequestResponse = new NewRequestResponse.fromJson(jsonResponse);
        print(newRequestResponse);

        setState(() {
          foodData = newRequestResponse.data.list;
          for (int i = 0; i < foodData.length; i++) {
            orderData = foodData[i].orderdata;
          }
        });
        setState(() {
          _isLoading = false;
        });
        return newRequestResponse;
      } else {
        setState(() {
          _isLoading = false;
        });
        return null;
      }
    } else {
      setState(() {
        _isLoading = false;
      });
      jsonResponse = json.decode(response.body.toString());
      newRequestResponse = new NewRequestResponse.fromJson(jsonResponse);
      print("onProcessRequest outside 200");
      return newRequestResponse;
    }
  }

  void getPrefs() async {
    sharedPreferences = await SharedPreferences.getInstance();
  }
}

1 个答案:

答案 0 :(得分:3)

这有点棘手,所以我希望我能理解该错误,但是对我来说,问题似乎出在您的getOnProcessRequest这行上:

for (int i = 0; i < foodData.length; i++) {         
        orderData = foodData[i].orderdata;
      }

您将在foodData的每个周期更新(并覆盖)orderData。我认为这不是正确的选择。

据我所知应该发生的是 对于每个foodData,获取orderData的列表。 但是foodData是一个列表,orderData也是。我认为您应该链接这些项目,以便对于每个foodData都可以访问其自己的orderData列表。

编辑: 我无法提供完整的解决方案,因为这会让我实在太多。 但是我想出了一个例子

final Map<String, dynamic> myApi = {
  "list": [
    {
      "id": 1,
      "orderdata": [
        {"title": "food1"},
        {"title": "food2"}
      ]
    },
    {
      "id": 2,
      "orderdata": [
        {"title": "food3"},
        {"title": "food4"}
      ]
    },
  ]
};

class OrderData {
  final String title;
  OrderData(this.title);

  @override
  String toString() {
    return title;
  }
}

class FoodData {
  final int id;
  final List<OrderData> orderData;
  FoodData(this.id, this.orderData);
}

void main() {
  final tmpMap = (myApi['list'] as List<Map<String, Object>>);
  print(tmpMap);
  List<FoodData> myList = tmpMap.map<FoodData>((elem) {
    final value = elem;
    final _id = value['id'] as int;
    final List<OrderData> _orderData =
        (value['orderdata'] as List<Map<String, String>>)
            .map<OrderData>((order) => OrderData(order['title']))
            .toList();
    return FoodData(_id, _orderData);
  }).toList();

  print(myList.length);
  for (int i = 0; i < myList.length; i++) {
    for (int j = 0; j < myList[i].orderData.length; j++) {
      print("i: $i, j: $j, elem: ${myList[i].orderData[j]}");
    }
  }
}

现在最后,您需要使用一个列表来更改getOnProcessRequest,因此删除您的orderdata,仅使用fooddata,现在foodData将具有每个元素(食物)也是订单的内部代表。

要实例化ListView.builder:

  1. 对于第一个(外部ListView),您将使用fooddata.length
  2. 对于第二个(内部ListView),您将使用foodata [i] .orders.length

希望这会帮助您找到正确的解决方案