Home > other >  Unhandled Exception: type 'Null' is not a subtype of type 'String' in Flutter
Unhandled Exception: type 'Null' is not a subtype of type 'String' in Flutter

Time:04-04

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.

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"] ?? '',  
  • Related