-2

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": "&laquo; Previous",
                "active": false
            },
            {
                "url": "https://achievexsolutions.in/current_work/eatiano/api/all_restaurant?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "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.

0

1 Answer 1

2

you could provide a fallback value in case it's null, for example to fallback to empty string do

nextPageUrl: json["next_page_url"] ?? '',  
Sign up to request clarification or add additional context in comments.

5 Comments

This was the first thing I tried prior to posting this question and I was highly hopeful that it would be key to solving this. But I still keep getting the same error. Do you think there's anything to be done in Line 154?
@coolhack7 I don't think so. And the check there is even unnecessary I would say. "url": url, would do the same as you now have.
Is this a common phenomenon when a lot of the values are null?
@coolhack7 the fromJson a few lines above that might be problematic though. there you maybe want to do url: json["url"] ?? '',
@coolhack7 another option is to simply make everything nullable, like String? url; instead of String url; but that might require to fix other parts of your code

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.