type 'List<dynamic>' is not a subtype of type 'String'

两盒软妹~` 提交于 2020-03-05 03:15:34

问题


It contains lots of list and nested objects. I need to display all the DishName from the json file

Json URL adress : Json address!! Check this out

i wanted to display the DishName in to my app in which there are lots of dishname in the json list. i parsed the json file using instantly parse json website. But now i dont know how to implent it on my app

code i wrote :

body: Container(
     child: Center(
      child: FutureBuilder(
        future:
            DefaultAssetBundle.of(context).loadString('jsons/data.json'),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          }
          var myData = jsonDecode(snapshot.data);
          final welcome = welcomeFromJson(myData);

          print(myData.length);
          return ListView.builder(
            itemBuilder: (BuildContext context, int index) {
              return Card(
                  child: ListTile(
                title: Text(welcome[index]
                    .tableMenuList[index]
                    .categoryDishes[index]
                    .dishName),
              ));
            },
            itemCount: myData == null ? 0 : myData.length,
          );
        },
      ),
    ),
  ),

i am getting error : type 'List' is not a subtype of type 'String'

this is the json class:-

// To parse this JSON data, do
//
//     final welcome = welcomeFromJson(jsonString);

import 'dart:convert';

List<Welcome> welcomeFromJson(String str) =>
    List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));

String welcomeToJson(List<Welcome> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Welcome {
  String restaurantId;
  String restaurantName;
  String restaurantImage;
  String tableId;
  String tableName;
  String branchName;
  String nexturl;
  List<TableMenuList> tableMenuList;

  Welcome({
    this.restaurantId,
    this.restaurantName,
    this.restaurantImage,
    this.tableId,
    this.tableName,
    this.branchName,
    this.nexturl,
    this.tableMenuList,
  });

  factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
        restaurantId: json["restaurant_id"],
        restaurantName: json["restaurant_name"],
        restaurantImage: json["restaurant_image"],
        tableId: json["table_id"],
        tableName: json["table_name"],
        branchName: json["branch_name"],
        nexturl: json["nexturl"],
        tableMenuList: List<TableMenuList>.from(
            json["table_menu_list"].map((x) => TableMenuList.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "restaurant_id": restaurantId,
        "restaurant_name": restaurantName,
        "restaurant_image": restaurantImage,
        "table_id": tableId,
        "table_name": tableName,
        "branch_name": branchName,
        "nexturl": nexturl,
        "table_menu_list":
            List<dynamic>.from(tableMenuList.map((x) => x.toJson())),
      };
}

class TableMenuList {
  String menuCategory;
  String menuCategoryId;
  String menuCategoryImage;
  String nexturl;
  List<CategoryDish> categoryDishes;

  TableMenuList({
    this.menuCategory,
    this.menuCategoryId,
    this.menuCategoryImage,
    this.nexturl,
    this.categoryDishes,
  });

  factory TableMenuList.fromJson(Map<String, dynamic> json) => TableMenuList(
        menuCategory: json["menu_category"],
        menuCategoryId: json["menu_category_id"],
        menuCategoryImage: json["menu_category_image"],
        nexturl: json["nexturl"],
        categoryDishes: List<CategoryDish>.from(
            json["category_dishes"].map((x) => CategoryDish.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "menu_category": menuCategory,
        "menu_category_id": menuCategoryId,
        "menu_category_image": menuCategoryImage,
        "nexturl": nexturl,
        "category_dishes":
            List<dynamic>.from(categoryDishes.map((x) => x.toJson())),
      };
}

class AddonCat {
  String addonCategory;
  String addonCategoryId;
  int addonSelection;
  String nexturl;
  List<CategoryDish> addons;

  AddonCat({
    this.addonCategory,
    this.addonCategoryId,
    this.addonSelection,
    this.nexturl,
    this.addons,
  });

  factory AddonCat.fromJson(Map<String, dynamic> json) => AddonCat(
        addonCategory: json["addon_category"],
        addonCategoryId: json["addon_category_id"],
        addonSelection: json["addon_selection"],
        nexturl: json["nexturl"],
        addons: List<CategoryDish>.from(
            json["addons"].map((x) => CategoryDish.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "addon_category": addonCategory,
        "addon_category_id": addonCategoryId,
        "addon_selection": addonSelection,
        "nexturl": nexturl,
        "addons": List<dynamic>.from(addons.map((x) => x.toJson())),
      };
}

class CategoryDish {
  String dishId;
  String dishName;
  double dishPrice;
  String dishImage;
  DishCurrency dishCurrency;
  int dishCalories;
  String dishDescription;
  bool dishAvailability;
  int dishType;
  String nexturl;
  List<AddonCat> addonCat;

  CategoryDish({
    this.dishId,
    this.dishName,
    this.dishPrice,
    this.dishImage,
    this.dishCurrency,
    this.dishCalories,
    this.dishDescription,
    this.dishAvailability,
    this.dishType,
    this.nexturl,
    this.addonCat,
  });

  factory CategoryDish.fromJson(Map<String, dynamic> json) => CategoryDish(
        dishId: json["dish_id"],
        dishName: json["dish_name"],
        dishPrice: json["dish_price"].toDouble(),
        dishImage: json["dish_image"],
        dishCurrency: dishCurrencyValues.map[json["dish_currency"]],
        dishCalories: json["dish_calories"],
        dishDescription: json["dish_description"],
        dishAvailability: json["dish_Availability"],
        dishType: json["dish_Type"],
        nexturl: json["nexturl"] == null ? null : json["nexturl"],
        addonCat: json["addonCat"] == null
            ? null
            : List<AddonCat>.from(
                json["addonCat"].map((x) => AddonCat.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "dish_id": dishId,
        "dish_name": dishName,
        "dish_price": dishPrice,
        "dish_image": dishImage,
        "dish_currency": dishCurrencyValues.reverse[dishCurrency],
        "dish_calories": dishCalories,
        "dish_description": dishDescription,
        "dish_Availability": dishAvailability,
        "dish_Type": dishType,
        "nexturl": nexturl == null ? null : nexturl,
        "addonCat": addonCat == null
            ? null
            : List<dynamic>.from(addonCat.map((x) => x.toJson())),
      };
}

enum DishCurrency { SAR }

final dishCurrencyValues = EnumValues({"SAR": DishCurrency.SAR});

class EnumValues<T> {
  Map<String, T> map;
  Map<T, String> reverseMap;

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

回答1:


I personally use this one for generating dart classes from JSON https://javiercbk.github.io/json_to_dart/

From my experience most of these automatic class builders are flawed to some extent and it is good practice to go over the generated dart manually. Or try your luck and walk the stack trace to see where parsing failed (usually when handling int and double from what I've seen).

Anyhow back to your problem, from looking at your code I see you are misusing indexes and generally having problems with json data structure:

               title: Text(welcome[index]
                .tableMenuList[index]
                .categoryDishes[index]
                .dishName),

The code above can easily throw "RangeError (index): Invalid value: Not in range..." (example if welcome[ 2 ] has only 1 tableMenuList). Even if all those arrays above are somehow the same length you would still not get the expected result.. The list would end up showing you 1st meal from the 1st menu list and 1st category dish, then next one would be 2nd meal from the 2nd menu and the 2nd restaurant.

Also because of the same reason as above the following code isn't enough:

itemCount: myData == null ? 0 : myData.length,

You need to have an itemCount for each of those lists you are using.

I've modified your code to work with the given JSON and changed a few things, in the end it looks like this.

I'm posting my source bellow, hopefully it will make things clearer for you:

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  http: any

welcome_model.dart

class Welcome {
  String restaurantId;
  String restaurantName;
  String restaurantImage;
  String tableId;
  String tableName;
  String branchName;
  String nexturl;
  List<TableMenuList> tableMenuList;

  Welcome(
      {this.restaurantId,
        this.restaurantName,
        this.restaurantImage,
        this.tableId,
        this.tableName,
        this.branchName,
        this.nexturl,
        this.tableMenuList});

  Welcome.fromJson(Map<String, dynamic> json) {
    restaurantId = json['restaurant_id'];
    restaurantName = json['restaurant_name'];
    restaurantImage = json['restaurant_image'];
    tableId = json['table_id'];
    tableName = json['table_name'];
    branchName = json['branch_name'];
    nexturl = json['nexturl'];
    if (json['table_menu_list'] != null) {
      tableMenuList = new List<TableMenuList>();
      json['table_menu_list'].forEach((v) {
        tableMenuList.add(new TableMenuList.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['restaurant_id'] = this.restaurantId;
    data['restaurant_name'] = this.restaurantName;
    data['restaurant_image'] = this.restaurantImage;
    data['table_id'] = this.tableId;
    data['table_name'] = this.tableName;
    data['branch_name'] = this.branchName;
    data['nexturl'] = this.nexturl;
    if (this.tableMenuList != null) {
      data['table_menu_list'] =
          this.tableMenuList.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class TableMenuList {
  String menuCategory;
  String menuCategoryId;
  String menuCategoryImage;
  String nexturl;
  List<CategoryDishes> categoryDishes;

  TableMenuList(
      {this.menuCategory,
        this.menuCategoryId,
        this.menuCategoryImage,
        this.nexturl,
        this.categoryDishes});

  TableMenuList.fromJson(Map<String, dynamic> json) {
    menuCategory = json['menu_category'];
    menuCategoryId = json['menu_category_id'];
    menuCategoryImage = json['menu_category_image'];
    nexturl = json['nexturl'];
    if (json['category_dishes'] != null) {
      categoryDishes = new List<CategoryDishes>();
      json['category_dishes'].forEach((v) {
        categoryDishes.add(new CategoryDishes.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['menu_category'] = this.menuCategory;
    data['menu_category_id'] = this.menuCategoryId;
    data['menu_category_image'] = this.menuCategoryImage;
    data['nexturl'] = this.nexturl;
    if (this.categoryDishes != null) {
      data['category_dishes'] =
          this.categoryDishes.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class CategoryDishes {
  String dishId;
  String dishName;
  double dishPrice;
  String dishImage;
  String dishCurrency;
  double dishCalories;
  String dishDescription;
  bool dishAvailability;
  int dishType;
  String nexturl;
  List<AddonCat> addonCat;

  CategoryDishes(
      {this.dishId,
        this.dishName,
        this.dishPrice,
        this.dishImage,
        this.dishCurrency,
        this.dishCalories,
        this.dishDescription,
        this.dishAvailability,
        this.dishType,
        this.nexturl,
        this.addonCat});

  CategoryDishes.fromJson(Map<String, dynamic> json) {
    dishId = json['dish_id'];
    dishName = json['dish_name'];
    dishPrice = json['dish_price'];
    dishImage = json['dish_image'];
    dishCurrency = json['dish_currency'];
    dishCalories = json['dish_calories'];
    dishDescription = json['dish_description'];
    dishAvailability = json['dish_Availability'];
    dishType = json['dish_Type'];
    nexturl = json['nexturl'];
    if (json['addonCat'] != null) {
      addonCat = new List<AddonCat>();
      json['addonCat'].forEach((v) {
        addonCat.add(new AddonCat.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['dish_id'] = this.dishId;
    data['dish_name'] = this.dishName;
    data['dish_price'] = this.dishPrice;
    data['dish_image'] = this.dishImage;
    data['dish_currency'] = this.dishCurrency;
    data['dish_calories'] = this.dishCalories;
    data['dish_description'] = this.dishDescription;
    data['dish_Availability'] = this.dishAvailability;
    data['dish_Type'] = this.dishType;
    data['nexturl'] = this.nexturl;
    if (this.addonCat != null) {
      data['addonCat'] = this.addonCat.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class AddonCat {
  String addonCategory;
  String addonCategoryId;
  int addonSelection;
  String nexturl;
  List<Addons> addons;

  AddonCat(
      {this.addonCategory,
        this.addonCategoryId,
        this.addonSelection,
        this.nexturl,
        this.addons});

  AddonCat.fromJson(Map<String, dynamic> json) {
    addonCategory = json['addon_category'];
    addonCategoryId = json['addon_category_id'];
    addonSelection = json['addon_selection'];
    nexturl = json['nexturl'];
    if (json['addons'] != null) {
      addons = new List<Addons>();
      json['addons'].forEach((v) {
        addons.add(new Addons.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['addon_category'] = this.addonCategory;
    data['addon_category_id'] = this.addonCategoryId;
    data['addon_selection'] = this.addonSelection;
    data['nexturl'] = this.nexturl;
    if (this.addons != null) {
      data['addons'] = this.addons.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Addons {
  String dishId;
  String dishName;
  double dishPrice;
  String dishImage;
  String dishCurrency;
  double dishCalories;
  String dishDescription;
  bool dishAvailability;
  int dishType;

  Addons(
      {this.dishId,
        this.dishName,
        this.dishPrice,
        this.dishImage,
        this.dishCurrency,
        this.dishCalories,
        this.dishDescription,
        this.dishAvailability,
        this.dishType});

  Addons.fromJson(Map<String, dynamic> json) {
    dishId = json['dish_id'];
    dishName = json['dish_name'];
    dishPrice = json['dish_price'];
    dishImage = json['dish_image'];
    dishCurrency = json['dish_currency'];
    dishCalories = json['dish_calories'];
    dishDescription = json['dish_description'];
    dishAvailability = json['dish_Availability'];
    dishType = json['dish_Type'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['dish_id'] = this.dishId;
    data['dish_name'] = this.dishName;
    data['dish_price'] = this.dishPrice;
    data['dish_image'] = this.dishImage;
    data['dish_currency'] = this.dishCurrency;
    data['dish_calories'] = this.dishCalories;
    data['dish_description'] = this.dishDescription;
    data['dish_Availability'] = this.dishAvailability;
    data['dish_Type'] = this.dishType;
    return data;
  }
}

welcome_page.dart

import 'package:flutter/material.dart';
import 'welcome_model.dart';
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:http/http.dart' as http;



class WelcomePage extends StatefulWidget {
  @override
  _WelcomePageState createState() => new _WelcomePageState();

}

class _WelcomePageState extends State<WelcomePage> {
  List<Welcome> welcomeList;
  bool isLoading = true;
  int selectedRestaurantIndex = 0;
  String titleString = "Restaurant";

  @override
  void initState() {
    super.initState();
    _fetchData();
  }


  @override
  void setState(fn) {
    if(mounted){
      super.setState(fn);
    }
  }


  @override
  void dispose() {
    super.dispose();
  }

  _fetchData() async{
    setState(() {
      isLoading = true;
    });
    // String url = Uri.encodeFull("http://www.mocky.io/v2/5dfccffc310000efc8d2c1ad"); // original json has only one restaurant
    // the one bellow has 3 restaurants,
    // 1st one was left untouched,
    // 2nd one (Steak house) has only "From The Barnyard" and "Fast Food" menu types
    // 3rd one (Bistro cafe) has only "Fresh From The Sea" and "Fast Food" menu types
    String url = Uri.encodeFull("http://www.mocky.io/v2/5e4aa68c2f0000690097d3f6");
    var parsedJson;
    try {
      http.Response response = await http.get(url).
      timeout(Duration(seconds: 10));
      if (response.statusCode == 200) {
        if (response.bodyBytes != null) {
           parsedJson = json.decode(utf8.decode(response.bodyBytes));
        }
      } else {
        print('RESPONSE CODE != 200 !');
      }
    } on TimeoutException catch (e) {
      print('Error: $e');
    } on SocketException catch (e) {
      print('Error: $e');
    } on Error catch (e) {
      print('Error: $e');
    }

    if(parsedJson!=null){
        if(parsedJson.length>0){
          welcomeList = new List<Welcome>();
          for(int i=0; i<parsedJson.length; i++) {
            try {
              welcomeList.add(Welcome.fromJson(parsedJson[i]));
            } catch (e, s){
              print('Eroor parsing from JSON! For # $i');
              print('Error: $e');
              print('Stacktrace: $s');
            }
          }
          if(welcomeList[0]!=null && welcomeList[0].restaurantName!=null) {
             titleString = welcomeList[0].restaurantName;
          }
        }
    }

    setState(() {
      isLoading = false;
    });

  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        backgroundColor: Colors.white,
        appBar: AppBar(
          iconTheme: IconThemeData(
            color: Colors.white,
          ),
          title: Text(titleString),
          centerTitle: true,
        ),
        drawer: Drawer(
          child: ListView(
                padding: EdgeInsets.zero,
                children: <Widget>[
                  DrawerHeader(
                    child: Text("Select a restaurant", style: TextStyle(color: Colors.white, fontSize: 28),textAlign: TextAlign.center,
                    ),
                    decoration: BoxDecoration(
                      color: Theme.of(context).primaryColor,
                    ),
                  ),
                  (welcomeList!=null && welcomeList.length>0) ?
                  ListView.builder(
                      shrinkWrap: true,
                      physics: ClampingScrollPhysics(),
                      itemCount: welcomeList.length,
                      itemBuilder: (BuildContext context, int index) {
                        return Padding(
                            padding: EdgeInsets.all(8),
                            child: RaisedButton(
                              onPressed: () {
                                setState(() {
                                  selectedRestaurantIndex = index;
                                  titleString = welcomeList[index].restaurantName.toString();
                                });
                                Navigator.pop(context);
                              },
                              padding: EdgeInsets.all(12),
                              child: Text(welcomeList[index].restaurantName.toString()),
                          )
                        );
                        ;}
                  )
                  : Text("No restaurants loaded...")
                ]
            )
        ),
        body: (isLoading)
          ? Center(child: CircularProgressIndicator(),)
          : Container(
              child: Center(
                 child: ListView.builder(
                  itemBuilder: (BuildContext context, int index1) {
                    return Card(
                        child: ListTile(
                          subtitle: Text(welcomeList[selectedRestaurantIndex].tableMenuList[index1].menuCategory.toString()),
                          title: ListView.builder(
                            shrinkWrap: true,
                            physics: ClampingScrollPhysics(),
                            itemBuilder: (BuildContext context, int index2) {
                            return Card(
                                child: ListTile(
                                    title: Text(welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes[index2].dishName.toString()),
                                ));
                          },
                          itemCount: (welcomeList[selectedRestaurantIndex].tableMenuList[index1] == null || welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes == null) ? 0 : (welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes.length) ,)
                        )
                    );
                  },
                  itemCount: (welcomeList == null || welcomeList[selectedRestaurantIndex] == null || welcomeList[selectedRestaurantIndex].tableMenuList == null) ? 0 : (welcomeList[selectedRestaurantIndex].tableMenuList.length) ,
                )
              ),
            ),
    );
  }
}

JSON with 3 restaurants here or here.



来源:https://stackoverflow.com/questions/60145694/type-listdynamic-is-not-a-subtype-of-type-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!