тип '_InternalLinkedHashMap 'не является подтипом' Article 'в приведении типа - PullRequest
0 голосов
/ 08 апреля 2020

Я получаю сообщение об ошибке, описанное в заголовке этого сообщения, я не могу расшифровать, что именно мне нужно сделать, чтобы правильно получить доступ к данным, которые я запрашиваю на веб-сайте. Код выглядит следующим образом:

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

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

Future<SearchNews> fetchNews() async {
  String key = 'xxx';
  final response =
  await http.get('https://newsapi.org/v2/everything?q=bitcoin&apiKey=$key');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return SearchNews.fromJson(json.decode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load news');
  }
}



class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      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> {
  Future<SearchNews> futureNews;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    futureNews = fetchNews();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
           FutureBuilder<SearchNews>(
             future: futureNews,
             builder: (context,snapshot) {
               if (snapshot.hasData) {
                 return Text(snapshot.data.articles[0].title);
               } else if (snapshot.hasError) {
                 return Text("${snapshot.error}");
               }
               return CircularProgressIndicator();
             }
           ),
          ],
        ),
      ),
    );
  }
}

class Source
{
  String id;
  String name;

  Source({this.id, this.name});
  factory Source.fromJson(Map<String, dynamic> json){
    return Source(
      id: json['id'],
      name: json['name'],
    );
  }
}

class Article
{
  Source source;
  String author;
  String title;
  String description;
  String url;
  String urlToImage;
  String publishedAt;
  String content;

  Article({this.source, this.author,this.title,this.description,this.url,this.urlToImage,this.publishedAt,this.content});
  factory Article.fromJson(Map<String, dynamic> json){
    return Article(
      source: json['source'],
      author: json['author'],
      title: json['title'],
      description: json['description'],
      url: json['url'],
      urlToImage: json['urlToImage'],
      publishedAt: json['publishedAt'],
      content: json['content'],
    );
  }
}

class SearchNews
{
  String status;
  int totalResults;
  List<Article> articles;

  SearchNews({this.status,this.totalResults,this.articles});
  factory SearchNews.fromJson(Map<String,dynamic>json){
    return SearchNews(
      status: json['status'],
      totalResults: json['totalResults'],
      articles: json['articles'].cast<Article>(),
    );
  }

}

Консоль при ошибке выдает следующее:

I/flutter ( 6644): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 6644): The following _CastError was thrown building FutureBuilder<SearchNews>(dirty, state:
I/flutter ( 6644): _FutureBuilderState<SearchNews>#43653):
I/flutter ( 6644): type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Article' in type cast
I/flutter ( 6644): 
I/flutter ( 6644): The relevant error-causing widget was:
I/flutter ( 6644):   FutureBuilder<SearchNews>
I/flutter ( 6644):   file:///xxx/main.dart:73:12
I/flutter ( 6644): 
I/flutter ( 6644): When the exception was thrown, this was the stack:
I/flutter ( 6644): #0      _CastListBase.[] (dart:_internal/cast.dart:101:46)
I/flutter ( 6644): #1      _MyHomePageState.build.<anonymous closure> (package:news_receiver_test/main.dart:77:52)
I/flutter ( 6644): #2      _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
I/flutter ( 6644): #3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4334:27)
I/flutter ( 6644): #4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4223:15)
I/flutter ( 6644): #5      Element.rebuild (package:flutter/src/widgets/framework.dart:3947:5)
I/flutter ( 6644): #6      BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2432:33)
I/flutter ( 6644): #7      WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:773:20)
I/flutter ( 6644): #8      RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:283:5)
I/flutter ( 6644): #9      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1102:15)
I/flutter ( 6644): #10     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1041:9)
I/flutter ( 6644): #11     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:957:5)
I/flutter ( 6644): #15     _invoke (dart:ui/hooks.dart:259:10)
I/flutter ( 6644): #16     _drawFrame (dart:ui/hooks.dart:217:3)
I/flutter ( 6644): (elided 3 frames from package dart:async)
I/flutter ( 6644): 
I/flutter ( 6644): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter ( 6644): Another exception was thrown: A RenderFlex overflowed by 99306 pixels on the bottom.
Lost connection to device.

До этого я сталкивался с ошибкой: type 'List is not подтип типа «Список» , от которого я затем избавился, добавив .cast<Article>() в конец строки: articles: json['articles'].cast<Article>(),

Ответы [ 2 ]

0 голосов
/ 08 апреля 2020

В этом примере вы пытаетесь привести сложный динамический тип c к сложному объекту. И эти типы несовместимы для выполнения прямого приведения в том виде, в котором оно выглядит.

Метод cast для dynamic представляется очень экспериментальным. Пожалуйста, обратитесь к этому ответу переполнения стека: В Дартс, синтаксически хороший способ привести динамику c к данному типу или вернуть ноль?

В вашем примере. Объект Article состоит из другого сложного объекта типа Source. И вы прямо пытаетесь привести объект dynamic к объекту Source в этом примере:

return Article(
      source: json['source'],
      author: json['author'],
      title: json['title'],
      description: json['description'],
      url: json['url'],
      urlToImage: json['urlToImage'],
      publishedAt: json['publishedAt'],
      content: json['content'],
    );

Вместо этого следует использовать метод Source.fromJson, который вы уже написали:

return Article(
      source: Source.fromJson(json['source']),
      author: json['author'],
      title: json['title'],
      description: json['description'],
      url: json['url'],
      urlToImage: json['urlToImage'],
      publishedAt: json['publishedAt'],
      content: json['content'],
    );

Аналогично, вы можете использовать fromJson метод Article в SearchNews.

factory SearchNews.fromJson(Map<String,dynamic>json){
    return SearchNews(
      status: json['status'],
      totalResults: json['totalResults'],
      articles: List<Article>.from(json["articles"].map((x) => Article.fromJson(x))),
    );
  }

Здесь мы конвертируем каждый элемент в объекте списка динамического c к статье, используя выражение map и ваш фабричный метод Article.fromJson, чтобы создать список типа List<Article>.

Надеюсь, это поможет.

0 голосов
/ 08 апреля 2020

Полагаю, у вас есть массив статей внутри json, возвращаемых удаленной службой.

Вы должны проанализировать массив статей.

Попробуйте что-то вроде этого. В SearchNews классе

factory SearchNews.fromJson(Map<String,dynamic>json){
  var auxList = json['articles'] as List;
  List<Article> listArticle = auxList.map((i) => 
  Article.fromJson(i)).toList();

  return SearchNews(
    status: json['status'],
    totalResults: json['totalResults'],
    articles: listArticle,
  );
}
...