英文:
Null is not a subType of String in my flutter newsapp
问题
正在使用 newsapi.org 开发一个新闻应用,用于从文章列表中获取数据,但在 Article.fromJson 中返回一个 null 不是 String 的异常。我想寻求一些帮助。谢谢。
//这是我的 Article 类
import 'package:news_app/source_models.dart';
class Article{
Source source;
String? author;
String? title;
String? description;
String? url;
String? content;
Article({required this.source,required this.author,required this.title,required this.description,required this.url,
required this.content});
factory Article.fromJson(Map<String,dynamic>json){
return Article(
source: Source.fromJson(json['source']),
author: json['author'] as String?,
title: json['title'] !=null?json['title'].toString():'',
description: json['description'] as String?,
url: json['url'] as String?,
content: json['content'] as String?,
);
}
Map<String,dynamic> toJson(Article article) => <String,dynamic>{
"source": article.source.toJson(),
"author": article.author,
"title": article.title,
"description": article.description,
"url": article.url,
"content": article.content,
};
}
//这是 API
import 'package:news_app/Article.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService{
static Future<List<Article>> article()async{
List<Article>? articles;
final http.Response response=await http.get(Uri.parse('https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
if(response.statusCode==200){
Map<String,dynamic> json=jsonDecode(response.body);
List<dynamic> body=json['articles'];
articles=body.map((item) => Article.fromJson(item)).toList();
}
return articles!;
}
}
//这是 Source 类
class Source{
String name;
Source({required this.name});
factory Source.fromJson(Map<String,dynamic> json){
return Source(
name:json['name']);
}
Map<String,dynamic> toJson(Source sources) => <String,dynamic>{
"name": sources.name,
};
}
//这是我的 UI
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:news_app/ApiService.dart';
import 'package:news_app/Article.dart';
class HomeScreen extends StatefulWidget{
createState()=>_HomeScreen();
}
class _HomeScreen extends State<HomeScreen>{
bool isWaiting=false;
List<Article>articles=[];
void initState(){
super.initState();
IncomingApi();
}
void IncomingApi()async{
isWaiting=true;
var data=await ApiService.article();
setState(() {
articles=data;
isWaiting=false;
});
}
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body:ListView.builder(
itemCount: articles.length,
itemBuilder:(context, index) {
return NewsContainer(context, articles[index]);
}) );
}
Widget NewsContainer(BuildContext context,Article article){
return Container(
child:ListTile(
title:Text(article.description!) ,
)
);
}
}
英文:
Am working on a newsapp using the newsapi.org to fetch data from the list of articles but it returns an exception of null is not a sub type of String in the Article.fromJson and i would like to ask for some help.Thank you
//this is my Article class
import 'package:news_app/source_models.dart';
class Article{
Source source;
String? author;
String? title;
String? description;
String? url;
String? content;
Article({required this.source,required this.author,required this.title,required this.description,required this.url,
required this.content});
factory Article.fromJson(Map<String,dynamic>json){
return Article(
source: Source.fromJson(json['source']),
author: json['author']as String,
title: json['title'] !=null?json['title'].toString():'',
description: json['description']as String,
url: json['url']as String,
content: json['content']as String,
);
}
Map<String,dynamic>ToJson(Article article)=><String,dynamic>
{
"source":article.source,
"author":article.author,
"title":article.title,
"description":article.description,
"url":article.url,
"content":article.content,
};
}
//this is the api
import 'package:news_app/Article.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService{
static Future<List<Article>>article()async{
List<Article>?articles;
final http.Response response=await http.get(Uri.parse('https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
if(response.statusCode==200){
Map<String,dynamic>json=jsonDecode(response.body);
List<dynamic>body=json['articles'];
articles=body.map((item) => Article.fromJson(item)).toList();
}
return articles!;
}
}
//this is the source class
class Source{
String name;
Source({required this.name});
factory Source.fromJson(Map<String,dynamic>json){
return Source(
name:json['name']);
}
Map<String,dynamic>ToJson(Source sources){
return <String,dynamic>{
"name":sources.name,
};
}
}
//this is my UI
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:news_app/ApiService.dart';
import 'package:news_app/Article.dart';
class HomeScreen extends StatefulWidget{
createState()=>_HomeScreen();
}
class _HomeScreen extends State<HomeScreen>{
bool isWaiting=false;
List<Article>articles=[];
void initState(){
super.initState();
IncomingApi();
}
void IncomingApi()async{
isWaiting=true;
var data=await ApiService.article();
setState(() {
articles=data;
isWaiting=false;
});
}
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body:ListView.builder(
itemCount: articles.length,
itemBuilder:(context, index) {
NewsContainer(context, articles[index]);
return Center(
child:CircularProgressIndicator()
);
}) );
}
Widget NewsContainer(BuildContext context,Article article){
return Container(
child:ListTile(
title:Text(article.description!) ,
)
);
}
}
//I made checks on all the fields but didnt work,i also tried using the futureBuilder and nothing comes out of it and i certainly dont clearly understand why the Source.fromJson didnt produce any exception if truely nothing is being passed on to the Article.fromJson.And please all answers will be appreciated.
答案1
得分: 3
由于一些输入可能为null
,你应该使用可空操作符?
将String
类型进行类型转换。
class Article {
Source source;
String? author;
String? title;
String? description;
String? url;
String? content;
Article({
required this.source,
required this.author,
required this.title,
required this.description,
required this.url,
required this.content,
});
factory Article.fromJson(Map<String, dynamic> json) {
return Article(
source: Source.fromJson(json['source']),
author: json['author'] as String?,
title: json['title'] != null ? json['title'].toString() : '',
description: json['description'] as String?,
url: json['url'] as String?,
content: json['content'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
"source": source,
"author": author,
"title": title,
"description": description,
"url": url,
"content": content,
};
}
}
注意:这段代码是使用Dart编写的,用于处理JSON数据的序列化和反序列化。在这段代码中,String?
表示字符串类型可以为空,as String?
是将JSON数据转换为可空的字符串类型。可空操作符?
用于处理可能为null
的情况。
英文:
As some of the inputs are null
, you should cast String
with nullable operator ?
.
class Article{
Source source;
String? author;
String? title;
String? description;
String? url;
String? content;
Article({required this.source,required this.author,required this.title,required this.description,required this.url,
required this.content});
factory Article.fromJson(Map<String,dynamic>json){
return Article(
source: Source.fromJson(json['source']),
author: json['author']as String?,
title: json['title'] !=null?json['title'].toString():'',
description: json['description']as String?,
url: json['url']as String?,
content: json['content']as String?,
);
}
Map<String,dynamic>ToJson()=><String,dynamic>
{
"source": source,
"author": author,
"title": title,
"description": description,
"url": url,
"content": content,
};
}
答案2
得分: 0
在你的代码中,作者字符串的键值为null,导致应用程序崩溃,所以你需要添加空安全性。你需要使用??
操作符代替!
。
另外,你可以从API响应中生成模型,查看这个链接。
还修复了你的代码中的一些警告。
请使用下面的代码替代你的模型类:
class ArticleResponse {
String? status;
int? totalResults;
List<Articles>? articles;
ArticleResponse({this.status, this.totalResults, this.articles});
ArticleResponse.fromJson(Map<String, dynamic> json) {
status = json['status'];
totalResults = json['totalResults'];
if (json['articles'] != null) {
articles = <Articles>[];
json['articles'].forEach((v) {
articles!.add(Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['status'] = status;
data['totalResults'] = totalResults;
if (articles != null) {
data['articles'] = articles!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Articles {
Source? source;
String? author;
String? title;
String? description;
String? url;
String? urlToImage;
String? publishedAt;
String? content;
Articles(
{this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content});
Articles.fromJson(Map<String, dynamic> json) {
source = json['source'] != null ? Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (source != null) {
data['source'] = source!.toJson();
}
data['author'] = author;
data['title'] = title;
data['description'] = description;
data['url'] = url;
data['urlToImage'] = urlToImage;
data['publishedAt'] = publishedAt;
data['content'] = content;
return data;
}
}
class Source {
String? id;
String? name;
Source({this.id, this.name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
API调用服务对于映射JSON到模型进行了一些小的更改。
class ApiService {
static Future<List<Articles>> article() async {
List<Articles>? articles;
final http.Response response = await http.get(Uri.parse(
'https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
final fetchData = ArticleResponse.fromJson(json);
articles = fetchData.articles ?? [];
}
return articles!;
}
}
主屏幕小部件如下:
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
createState() => _HomeScreen();
}
class _HomeScreen extends State<HomeScreen> {
bool isWaiting = false;
List<Articles> articles = [];
@override
void initState() {
super.initState();
incomingApi();
}
Future<void> incomingApi() async {
isWaiting = true;
List<Articles> data = await ApiService.article();
setState(() {
articles = data;
isWaiting = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: isWaiting
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: articles.length,
itemBuilder: (context, index) {
return newsContainer(context, articles[index]);
}),
);
}
Widget newsContainer(BuildContext context, Articles article) {
return ListTile(
title: Text(article.description ?? '');
}
}
}
英文:
in your code author string key value is null so app is crashing so here you need to add null-safety. so you need to user ??
operator instead of !
.
also you can generate model from API response checkout this link
Also fixed few warnings in your code.
Prefere bellow code.
Replace your Model classes
class ArticleResponse {
String? status;
int? totalResults;
List<Articles>? articles;
ArticleResponse({this.status, this.totalResults, this.articles});
ArticleResponse.fromJson(Map<String, dynamic> json) {
status = json['status'];
totalResults = json['totalResults'];
if (json['articles'] != null) {
articles = <Articles>[];
json['articles'].forEach((v) {
articles!.add(Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['status'] = status;
data['totalResults'] = totalResults;
if (articles != null) {
data['articles'] = articles!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Articles {
Source? source;
String? author;
String? title;
String? description;
String? url;
String? urlToImage;
String? publishedAt;
String? content;
Articles(
{this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content});
Articles.fromJson(Map<String, dynamic> json) {
source = json['source'] != null ? Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (source != null) {
data['source'] = source!.toJson();
}
data['author'] = author;
data['title'] = title;
data['description'] = description;
data['url'] = url;
data['urlToImage'] = urlToImage;
data['publishedAt'] = publishedAt;
data['content'] = content;
return data;
}
}
class Source {
String? id;
String? name;
Source({this.id, this.name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
API Call service minor changes to map json in model.
class ApiService {
static Future<List<Articles>> article() async {
List<Articles>? articles;
final http.Response response = await http.get(Uri.parse(
'https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
final fetchData = ArticleResponse.fromJson(json); // just need to add json response to map model
articles = fetchData.articles ?? []; // get article array from response.
}
return articles!;
}
}
Home screen widget
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
createState() => _HomeScreen();
}
class _HomeScreen extends State<HomeScreen> {
bool isWaiting = false;
List<Articles> articles = [];
@override
void initState() {
super.initState();
incomingApi();
}
Future<void> incomingApi() async {
isWaiting = true;
List<Articles> data = await ApiService.article();
setState(() {
articles = data;
isWaiting = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: isWaiting
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: articles.length,
itemBuilder: (context, index) {
return newsContainer(context, articles[index]);
}),
);
}
Widget newsContainer(BuildContext context, Articles article) {
return ListTile(
title: Text(article.description ?? ''),
);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论