web-dev-qa-db-ja.com

リストからFlutter JSON文字列をマッピングする方法は?

YouTube JSON URLから応答を文字列として正常に出力していますが、「アイテム」を介してシリアル化しようとすると、次のエラー_Unhandled exception: type 'List' is not a subtype of type 'Map' of 'json' where List is from Dart:core Map is from Dart:core_が表示されます

ここに私のコードがあります...

_class CardInfo {
  //Constructor
  String id;
  String description;
  String role;
  //int score;

  CardInfo.fromJson(Map json) {
    this.id = json['vieoId'];
    this.description = json['description'];
    this.role = json['title'];
    //this.score = json['score'];
  }
}

Future getData() async {
    String url = 'YouTube url';
    var httpClient  = createHttpClient();
    var response = await httpClient.get(url);
    Map data = JSON.decode(response.body);
    //String ip = data['items'];
    var ci = new CardInfo.fromJson(data['items']);

    //print(data['items']);
    print(ci.id);
    //print(ci.description);
    //print(ci.role);

    if (!mounted) return;


    setState(() {});

  }
_

_print(data['items']_は印刷されますが、print(ci.id)または任意のカード情報変数は上記のエラーをスローします。

**** print(data);のログ

_{kind: youtube#searchListResponse, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/P9wyOxsXEuXOCvj7znCun2-EykU", nextPageToken: CAMQAA, regionCode: US, pageInfo: {totalResults: 1000000, resultsPerPage: 3}, items: [{kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/Csl1kQhnOsbs0j4_336zJAN176k", id: {kind: youtube#video, videoId: e3pUxU_bE6w}, snippet: {publishedAt: 2017-09-14T09:43:17.000Z, channelId: UCbD8EppRX3ZwJSou-TVo90A, title: [PRISTIN - We Like] KPOP TV Show | M COUNTDOWN 170914 EP.541, description: KPOP Chart Show M COUNTDOWN | EP.541 - PRISTIN - We Like ▷Watch more video clips: http://MCOUNTDOWN-KPOP2017 [Kor Ver.] 프리티 ..., thumbnails: {default: {url: https://i.ytimg.com/vi/e3pUxU_bE6w/default.jpg, width: 120, height: 90}, medium: {url: https://i.ytimg.com/vi/e3pUxU_bE6w/mqdefault.jpg, width: 320, height: 180}, high: {url: https://i.ytimg.com/vi/e3pUxU_bE6w/hqdefault.jpg, width: 480, height: 360}}, channelTitle: Mnet K-POP, liveBroadcastContent: none}}, {kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/1JCCNBPNbFeusCp_9-pl4i8q5OU", id: {kind: youtube#video, videoId: Cc4hO9RLdl4}, snippet: {publishedAt: 2017-09-14T10:37:29.000Z, channelId: UCbD8EppRX3ZwJSou-TVo90A, title: [EXO - Power] KPOP TV Show | M COUNTDOWN 170914 EP.541, description: KPOP Chart Show M COUNTDOWN | EP.541 - EXO - Power ▷Watch more video clips: http://MCOUNTDOWN-KPOP2017 [Kor Ver.] Power Up! '#EXO' 여기 ..., thumbnails: {default: {url: https://i.ytimg.com/vi/Cc4hO9RLdl4/default.jpg, width: 120, height: 90}, medium: {url: https://i.ytimg.com/vi/Cc4hO9RLdl4/mqdefault.jpg, width: 320, height: 180}, high: {url: https://i.ytimg.com/vi/Cc4hO9RLdl4/hqdefault.jpg, width: 480, height: 360}}, channelTitle: Mnet K-POP, liveBroadcastContent: none}}, {kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/ZnYC4e5evyfldkM67HsDuV8Yh3E", id: {kind: youtube#video, videoId: BBcOM25wrVo}, snippet: {publishedAt: 2017-08-18T15:21:48.000Z, channelId: UCtFtO4By4czgkYGvEXvJu0A, title: Kpop Banned Dance: MV vs LIVE, description: Kpop Banned Dance: MV vs LIVE Koreas biggest broadcasting companies has strict rules and standards on what lyrics and dances moves can be performed., thumbnails: {default: {url: https://i.ytimg.com/vi/BBcOM25wrVo/default.jpg, width: 120, height: 90}, medium: {url: https://i.ytimg.com/vi/BBcOM25wrVo/mqdefault.jpg, width: 320, height: 180}, high: {url: https://i.ytimg.com/vi/BBcOM25wrVo/hqdefault.jpg, width: 480, height: 360}}, channelTitle: Kpop Corn, liveBroadcastContent: none}}]}
_

***ループ文で更新

ここに_for loop_エラーを返す__type 'String' is not a subtype of type 'int' of 'index'_のコードがあります...

_Map data = JSON.decode(response);
var videos = data['items'];
for (var items in videos['snippet']){
      print(items);
    }
_

_items in videos_でループを実行すると、探している3つのビデオ(スニペットを含む)の3つの個別のエントリが得られます。個々のスニペットを取得しようとすると失敗します。正しい方向を教えてください。

5
Charles Jr

data['items']ListではなくMap(つまりJSON配列)です。

ここで役立つリスト内包法を使用できます。

final items = (data['items'] as List).map((i) => new CardInfo.fromJson(i));
for (final item in items) {
  print(item.id);
}
16
matanlurey

次の行は、Listitemsを示しています。

var videos = data['items'];

この行のためにエラーが発生します

for(var items in videos['snippet'])

前の行では、snippet内のデータを反復処理していると思いますが、実際には、ビデオのリスト内のインデックス「スニペット」を反復処理しようとしています。 videos[0] , videos [1], videos [2] .. String'snippet'を渡している間

まず、videosリスト項目を項目ごとに繰り返す必要があります(各項目はマップです)。各Mapを変数に格納します。 myMap['snippet']snippetの値にアクセスできます

    Map data = JSON.decode(response);
    var videos = data['items']; //returns a List of Maps
    for (var items in videos){ //iterate over the list
    Map myMap = items; //store each map 
    print(myMap['snippet']);
        }

これで問題が解決するかどうかを確認してください。

1
aziza

私はこれを共有したいと思います、そして何人かの専門家もこのコードを改善してください、何時間もそれと戦います。

モデルクラス

class Testimony{
    String fullname;
   String testimony;

   Testimony({this.fullname,
     this.testimony}); 

    factory Testimony.fromJson(Map<String, dynamic> json) => new Testimony(
      fullname: json['fullname'] as String,
       testimony: json['testimony'] as String,  
         );

         }

APIクラス

List<Testimony> ToListandMap (String responseBody) {
 Map data = json.decode(responseBody);
    var videos = data['testimonies']; //returns a List of Maps
  final casting =  videos.cast<Map<String, dynamic>>();
   return casting.map<Testimony>((json) => Testimony.fromJson(json)).toList();
    }

Future<List<Testimony>> fetchTestimonies(http.Client client) async {
       final response = await client.get('https://tryjambcbt.com/api/testimonies');

         return ToList(response.body);
         }

Iのメインウィジェット

FutureBuilder<List<Testimony>>(
    future: fetchTestimonies(http.Client()),
    builder: (context, snapshot) {
      if (snapshot.hasError) print(snapshot.error);
      return snapshot.hasData
          ? TestimonyList(testimony: snapshot.data)
          : Center(child: CircularProgressIndicator());
    },
  ),

ウィジェット

class TestimonyList extends StatelessWidget {
final List<Testimony> testimony;

TestimonyList({Key key, this.testimony}) : super(key: key);

  @override
 Widget build(BuildContext context) {
  return ListView.builder(
    physics: BouncingScrollPhysics(),
    padding: EdgeInsets.only(bottom: 10),
    shrinkWrap: true,
    scrollDirection: Axis.vertical,
    itemCount: testimony.length,
    itemBuilder: (context, index) {
    return Padding(
      padding: EdgeInsets.only(right: 10),
      child: Text(testimony[index].testimony)
       );
      },
    );
   }
  }
0
Harbdollar