I have encountered a very unusual problem while trying to get an app to execute. I keep getting the above error when I run the project using flutter run --release --verbose
. I believe it has something to do with specific fields in the JSON response being null that I'm receiving from the server. This response, when converted to a Dart model class probably doesn't recognize these null values which is why I assume I keep getting the error stated in the title. I would like to know if there's anything I can do to go around this and get my app to render the data from the response that I want. The complete error log is below(I will also mark the line numbers mentioned below with comments in the model.dart
widget):
[ 2084 ms] E/flutter ( 9822): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not asubtype of type 'String'
[ 1 ms] E/flutter ( 9822): #0 new Link.fromJson (package:popular_restaurants/model.dart:154)
[ 1 ms] E/flutter ( 9822): #1 new Data.fromJson.<anonymous closure>
(package:popular_restaurants/model.dart:71)
[ 1 ms] E/flutter ( 9822): #2 MappedListIterable.elementAt (dart:_internal/iterable.dart:413)
[ 1 ms] E/flutter ( 9822): #3 ListIterator.moveNext (dart:_internal/iterable.dart:342)
[ 1 ms] E/flutter ( 9822): #4 new List.from (dart:core-patch/array_patch.dart:41)
[ 1 ms] E/flutter ( 9822): #5 new Data.fromJson (package:popular_restaurants/model.dart:71)
[ ] E/flutter ( 9822): #6 new Restaurants.fromJson (package:popular_restaurants/model.dart:24)
[ 1 ms] E/flutter ( 9822): #7 restaurantsFromJson (package:popular_restaurants/model.dart:9)
[ 1 ms] E/flutter ( 9822): #8 ProviderClass.fetchRestaurants
(package:popular_restaurants/providerClass.dart:22)
[ 2 ms] E/flutter ( 9822): <asynchronous suspension>
[ 1 ms] E/flutter ( 9822):
This is the JSON response:
{
"status": "200",
"data": {
"current_page": 1,
"data": [
{
"restaurant_id": 1,
"restaurant_name": "City Club",
"restaurant_address": "Street Number 17, GN Block, Sector V, Bidhannagar, Kolkata, West Bengal 700091",
"restaurant_image": "/public/assets/restaurant/6x4aJL03-36-30.jpg",
"restaurant_rating": "4",
"restaurant_rating_count": "8",
"distance": 0
},
{
"restaurant_id": 6,
"restaurant_name": "Mocambo",
"restaurant_address": "Ground Floor, 25B, Mirza Ghalib St, Taltala, Kolkata, West Bengal 700016",
"restaurant_image": "/public/assets/restaurant/A6lAQu03-41-17.jpg",
"restaurant_rating": "4",
"restaurant_rating_count": "8",
"distance": 14.8039003284490693346242551342584192752838134765625
},
{
"restaurant_id": 7,
"restaurant_name": "Peter Cat",
"restaurant_address": "Park St, opposite KFC Restaurant, Park Street area, Kolkata, West Bengal 700016",
"restaurant_image": "/public/assets/restaurant/RfjxvK03-44-59.jpg",
"restaurant_rating": "4",
"restaurant_rating_count": "8",
"distance": 47.4211446933120015501117450185120105743408203125
},
{
"restaurant_id": 8,
"restaurant_name": "Flurrys",
"restaurant_address": "Grand Trunk Rd, Barabazar, Sukhsanatantala, Chandannagar, West Bengal 712136",
"restaurant_image": "/public/assets/restaurant/Pitmxq03-47-20.jpg",
"restaurant_rating": "4",
"restaurant_rating_count": "8",
"distance": 116.161207301201244490584940649569034576416015625
},
{
"restaurant_id": 9,
"restaurant_name": "Karims",
"restaurant_address": "GP Block, Sector V, Bidhannagar, Kolkata, West Bengal 700091",
"restaurant_image": "/public/assets/restaurant/brmWnW03-51-13.jpg",
"restaurant_rating": "4",
"restaurant_rating_count": "8",
"distance": 179.675331121963466785018681548535823822021484375
}
],
"first_page_url": "https://achievexsolutions.in/current_work/eatiano/api/all_restaurant?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://achievexsolutions.in/current_work/eatiano/api/all_restaurant?page=1",
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "https://achievexsolutions.in/current_work/eatiano/api/all_restaurant?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"next_page_url": null,
"path": "https://achievexsolutions.in/current_work/eatiano/api/all_restaurant",
"per_page": 25,
"prev_page_url": null,
"to": 5,
"total": 5
}
}
model.dart
import 'package:meta/meta.dart';
import 'dart:convert';
Restaurants restaurantsFromJson(String str) => Restaurants.fromJson(json.decode(str));
//Line 9
String restaurantsToJson(Restaurants data) => json.encode(data.toJson());
class Restaurants {
Restaurants({
required this.status,
required this.data,
});
final String status;
final Data data;
factory Restaurants.fromJson(Map<String, dynamic> json) => Restaurants(
status: json["status"],
data: Data.fromJson(json["data"]),
); //Line 24
Map<String, dynamic> toJson() => {
"status": status,
"data": data.toJson(),
};
}
class Data {
Data({
required this.currentPage,
required this.data,
required this.firstPageUrl,
required this.from,
required this.lastPage,
required this.lastPageUrl,
required this.links,
required this.nextPageUrl,
required this.path,
required this.perPage,
required this.prevPageUrl,
required this.to,
required this.total,
});
final int currentPage;
final List<Datum> data;
final String firstPageUrl;
final int from;
final int lastPage;
final String lastPageUrl;
final List<Link> links;
final dynamic nextPageUrl;
final String path;
final int perPage;
final dynamic prevPageUrl;
final int to;
final int total;
factory Data.fromJson(Map<String, dynamic> json) => Data(
currentPage: json["current_page"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
firstPageUrl: json["first_page_url"],
from: json["from"],
lastPage: json["last_page"],
lastPageUrl: json["last_page_url"],
links: List<Link>.from(json["links"].map((x) => Link.fromJson(x))),
nextPageUrl: json["next_page_url"], //Line Number 71
path: json["path"],
perPage: json["per_page"],
prevPageUrl: json["prev_page_url"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"current_page": currentPage,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"first_page_url": firstPageUrl,
"from": from,
"last_page": lastPage,
"last_page_url": lastPageUrl,
"links": List<dynamic>.from(links.map((x) => x.toJson())),
"next_page_url": nextPageUrl,
"path": path,
"per_page": perPage,
"prev_page_url": prevPageUrl,
"to": to,
"total": total,
};
}
class Datum {
Datum({
required this.restaurantId,
required this.restaurantName,
required this.restaurantAddress,
required this.restaurantImage,
required this.restaurantRating,
required this.restaurantRatingCount,
required this.distance,
});
final int restaurantId;
final String restaurantName;
final String restaurantAddress;
final String restaurantImage;
final String restaurantRating;
final String restaurantRatingCount;
final double distance;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
restaurantId: json["restaurant_id"],
restaurantName: json["restaurant_name"],
restaurantAddress: json["restaurant_address"],
restaurantImage: json["restaurant_image"],
restaurantRating: json["restaurant_rating"],
restaurantRatingCount: json["restaurant_rating_count"],
distance: json["distance"].toDouble(),
);
Map<String, dynamic> toJson() => {
"restaurant_id": restaurantId,
"restaurant_name": restaurantName,
"restaurant_address": restaurantAddress,
"restaurant_image": restaurantImage,
"restaurant_rating": restaurantRating,
"restaurant_rating_count": restaurantRatingCount,
"distance": distance,
};
}
class Link {
Link({
required this.url,
required this.label,
required this.active,
});
final String url;
final String label;
final bool active;
factory Link.fromJson(Map<String, dynamic> json) => Link(
url: json["url"] == null ? null : json["url"],
label: json["label"],
active: json["active"],
);
Map<String, dynamic> toJson() => {
"url": url == null ? null : url, //This is line 154
"label": label,
"active": active,
};
}
provider.dart(This is where the API call is being made)
class ProviderClass with ChangeNotifier {
String baseUrl = 'https://achievexsolutions.in/current_work/eatiano/';
Map<String, dynamic> _restaurants = {};
final queryParams = {'lat': '22.5735314', 'lng': '88.4331189'};
Map<String, dynamic> get restaurants {
return {..._restaurants};
}
Future<void> fetchRestaurants() async {
final url = Uri.parse(baseUrl
'api/all_restaurant'
'?'
'lat=${queryParams['lat']}'
'&'
'lng=${queryParams['lng']}');
final response = await http.get(url);
Restaurants restaurantsModel = restaurantsFromJson(response.body);
_restaurants = restaurantsModel.toJson();
print(_restaurants);
}
}
The widget(Owing to the error, the circular progress keeps spinning. I try printing the names of the restaurant's):
class MainScreenState extends State<MainScreen> {
bool isLoading = true;
@override
void initState() {
// TODO: implement initState
Provider.of<ProviderClass>(context, listen: false)
.fetchRestaurants()
.then((_) {
setState(() {
isLoading = false;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<ProviderClass>(context).restaurants;
// TODO: implement build
return Scaffold(
body: isLoading
? const Center(
child: CircularProgressIndicator(
color: Colors.red,
),
)
: Container(
height: 800,
width: double.infinity,
child: ListView.builder(
itemBuilder: (context, index) =>
Text(provider['data']['data'][index]['restaurant_name']),
itemCount: provider['data']['data'].length,
),
),
);
}
}
P.S: The entire point of doing flutter run --release --verbose
was to check what was causing this error in the release file. I get the desired output on the emulator which I believe runs the debug.apk. This is also the same on an actual device. But it's the release apk that keeps throwing this error.
CodePudding user response:
you could provide a fallback value in case it's null, for example to fallback to empty string do
nextPageUrl: json["next_page_url"] ?? '',