0
votes

here is the response

{
"overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground "fight clubs" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
"title": "Fight Club",
}

the model

class Movies {
  String title;
  String overview;
  

  Movies(
      {this.title , this.overview});

      factory Movies.fromJson(Map <String, dynamic> parsedJson){
        return Movies(title: parsedJson['title'] , overview: parsedJson['overview']);
      }

}

and

  Future <List<Movies>> fetchMovies () async {
    var response = await http.get(url);
    var jsonData = jsonDecode(response.body) as List ;
    List<Movies> movies = jsonData.map((e) => Movies.fromJson(e)).toList();
    
    print(movies.length);
    return movies;

  }

I get this error (Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List' in type cast) no matter what i do

3
Can you please attach sample json response from http.get? Additionally the response.body will be a key value pair so casting it directly to List is creating above issue. - Tanuj

3 Answers

1
votes

You tried to cast jsonData as List but the decoder says it's of type Map (Also your response shows its of type Map)

Future <List<Movies>> fetchMovies () async {
  var response = await http.get(url);
  var jsonData = jsonDecode(response.body);
  if(jsonData is List) //check if it's a List
    return List<Movies>.from(jsonData.map(map) => Movies.fromJson(map));
  else if(jsonData is Map) //check if it's a Map
    return [Movies.fromJson(jsonData)]; //return a List of length 1

}
0
votes

You can copy paste run full code below
You can use moviesFromJson and display with FutureBuilder
code snippet

List<Movies> moviesFromJson(String str) =>
    List<Movies>.from(json.decode(str).map((x) => Movies.fromJson(x)));
    
if (response.statusCode == 200) {
      return moviesFromJson(jsonString);

working demo

enter image description here

full code

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

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

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

class Movies {
  Movies({
    this.overview,
    this.title,
  });

  String overview;
  String title;

  factory Movies.fromJson(Map<String, dynamic> json) => Movies(
        overview: json["overview"],
        title: json["title"],
      );

  Map<String, dynamic> toJson() => {
        "overview": overview,
        "title": title,
      };
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  Future<List<Movies>> _future;

  Future<List<Movies>> fetchMovies() async {
    String jsonString = '''
    [{
"overview" : "with underground \\"fight clubs\\" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion",
"title" : "Fight Club"
},
{
"overview" : "test overview",
"title" : "test title"
}
]
    ''';

    var response = http.Response(jsonString, 200);

    if (response.statusCode == 200) {
      return moviesFromJson(jsonString);
    } else {
      print(response.statusCode);
    }
  }

  @override
  void initState() {
    _future = fetchMovies();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: FutureBuilder(
            future: _future,
            builder: (context, AsyncSnapshot<List<Movies>> snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return Text('none');
                case ConnectionState.waiting:
                  return Center(child: CircularProgressIndicator());
                case ConnectionState.active:
                  return Text('');
                case ConnectionState.done:
                  if (snapshot.hasError) {
                    return Text(
                      '${snapshot.error}',
                      style: TextStyle(color: Colors.red),
                    );
                  } else {
                    return ListView.builder(
                        itemCount: snapshot.data.length,
                        itemBuilder: (context, index) {
                          return Card(
                              elevation: 6.0,
                              child: Padding(
                                padding: const EdgeInsets.only(
                                    top: 6.0,
                                    bottom: 6.0,
                                    left: 8.0,
                                    right: 8.0),
                                child: Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Text(snapshot.data[index].title),
                                    Spacer(),
                                    Expanded(
                                      child: Text(
                                        snapshot.data[index].overview,
                                      ),
                                    ),
                                  ],
                                ),
                              ));
                        });
                  }
              }
            }));
  }
}
0
votes

Just check out he answer

[
    {
       "overview":"A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground \"fight clubs\" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
       "title":"Fight Club"
    },
    {
       "overview":"A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground fight clubs forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
       "title":"second Club"
    }
 ]

Model

// To parse this JSON data, do
//
//     final movies = moviesFromJson(jsonString);

import 'dart:convert';

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

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

class Movies {
    Movies({
        this.overview,
        this.title,
    });

    String overview;
    String title;

    factory Movies.fromJson(Map<String, dynamic> json) => Movies(
        overview: json["overview"],
        title: json["title"],
    );

    Map<String, dynamic> toJson() => {
        "overview": overview,
        "title": title,
    };
}

ui page :

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:json_parsing_example/models.dart';

// To parse this JSON data, do
//
//     final user = userFromJson(jsonString);

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Users'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isLoading = false;
  List<Movies> dataList = List();
  Future<String> loadFromAssets() async {
    return await rootBundle.loadString('json/parse.json');
  }

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

  getData() async {
    setState(() {
      _isLoading = true;
    });
    String jsonString = await loadFromAssets();
    final movies = moviesFromJson(jsonString);

    dataList = movies;

    setState(() {
      _isLoading = false;
    });
  }
    // In your case you just check out this code check out the model class
  /* Future <List<Movies>> fetchMovies () async {
    var response = await http.get(url);
    return moviesFromJson(response.body);

  } */

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: _isLoading
          ? Center(
              child: CircularProgressIndicator(),
            )
          : Container(
              child: ListView.builder(
                  itemCount: dataList.length,
                  shrinkWrap: true,
                  itemBuilder: (context, i) {
                    return Card(
                        child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Text(dataList[i].overview),
                    ));
                  }),
            ),
    );
  }
}

And on thing to tell is the value for the overview has the double quotes which is why there might be some parsing problem just check the code and let me know if it works.