Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
5.8k views
in Technique[技术] by (71.8m points)

flutter - List<dynamic> is not a subtype of type 'string' in type cast

I am trying to post my data which consist an array of cartItems and other information. But could not get through it.

The api from laravel is generated as follows like in imageenter image description here

My Request with postman

enter image description here

I am getting below error in the logcat:

   type 'List<dynamic>' is not a subtype of type 'String' in type cast

E/flutter (13443): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The getter 'statusCode' was called on null.
E/flutter (13443): Receiver: null
E/flutter (13443): Tried calling: statusCode
E/flutter (13443): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter (13443): #1      new ResponseApi (package:kitabyatra/response/ResponseApi.dart:11:21)
E/flutter (13443): #2      ContentRepositoryImpl.dopostApiCallWithToken (package:kitabyatra/repository/ContentRepositoryImpl.dart:184:41)
E/flutter (13443): <asynchronous suspension>
E/flutter (13443): #3      ContentRepositoryImpl.doAddOrderApiCall (package:kitabyatra/repository/ContentRepositoryImpl.dart:515:18)
E/flutter (13443): #4      CheckoutPresenter.doAddOrderApiCall (package:kitabyatra/view/checkout/CheckoutPresenter.dart:552:81)
E/flutter (13443): #5      CheckoutState._buildDeliveryLocation.<anonymous closure> (package:kitabyatra/view/checkout/CheckoutView.dart:303:35)
E/flutter (13443): #6      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
E/flutter (13443): #7      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1111:38)
E/flutter (13443): #8      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
E/flutter (13443): #9      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:598:11)
E/flutter (13443): #10     BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:287:5)
E/flutter (13443): #11     BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:259:7)
E/flutter (13443): #12     GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
E/flutter (13443): #13     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:362:20)
E/flutter (13443): #14     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
E/flutter (13443): #15     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
E/flutter (13443): #16     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
E/flutter (13443): #17     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
E/flutter (13443): #18     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
E/flutter (13443): #19     _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (13443): #20     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (13443): #21     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (13443): #22     _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter (13443): #23     _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)

My Response Api class

    class ResponseApi {

  int code;
  String body;
  String errorMessage;

  ResponseApi(Response response)
  {
    code = response.statusCode;

    if (isSuccessful())
    {
      body = response.body;
      errorMessage = '';
    }
    else
    {
      body = response.body;
      errorMessage = "";
    }
  }

  bool isSuccessful()
  {
    return code >= 100 && code < 600;
  }
}

I have implemented the postcall method as follows:

 @override
  Future<ResponseFormat<ResponseAddOrder>> doAddOrderApiCall(
      Map<String, dynamic> map) async {
    final String url = liveUrl + "user/order/product";
    print("Add Order ");
    print(url);
    return await dopostApiCallWithToken<ResponseAddOrder, ResponseAddOrder>(
        ResponseAddOrder(), url, map);
  }

I have handled my post method as follows:

@override
  Future<ResponseFormat<R>> dopostApiCallWithToken<T extends ResponseUni, R>(
      T obj, String url, Map map) async {
    Map valueMap = json.decode(JsonEncoder().convert(map));
    SecureStorageRepositoryImpl secureStorageRepositoryImpl =
        SecureStorageRepositoryImpl();
    String apiToken = await secureStorageRepositoryImpl.getApiToken();

    if (apiToken == null) {
      apiToken = "";
    }

    final Client client = http.Client();
    Map<String, String> requestHeaders = {'authorization': apiToken};
    try {
      final response = await http
          .post(
        '$url',
        headers: requestHeaders,
        body: valueMap,
      )
          .catchError((dynamic e) {
      
        print("${e.toString()}");
      });

print(response); ------>>> // Here I am getting null 

      final ResponseApi psApiResponse = ResponseApi(response);
      print(psApiResponse.errorMessage);
      print(psApiResponse.code);
      if (psApiResponse.isSuccessful()) {
        final dynamic hashMap = json.decode(response.body);

        if (!(hashMap is Map)) {
          final List<T> tList = <T>[];
          hashMap.forEach((dynamic data) {
            tList.add(obj.fromMap(data));
          });
          return ResponseFormat<R>(Status.SUCCESS, '', tList ?? R);
        } else {
          return ResponseFormat<R>(Status.SUCCESS, '', obj.fromMap(hashMap));
        }
      } else {
        return ResponseFormat<R>(
            Status.ERROR, psApiResponse.errorMessage, null);
      }
    } finally {
      client.close();
    }
  }

I have created my Request class as follows:

class RequestCheckOut extends RequestUni<RequestCheckOut> {
  RequestCheckOut({

    this.cartList,
    this.paymentId,
    this.price,
    this.deliveryAddressId,
    this.billingAddressId,
    this.discount,
    this.deliveryCharge,
    this.finalPrice,

  });
  var cartList;
  String paymentId;
  String price;
  String deliveryAddressId;
  String billingAddressId;
  String discount;
  String deliveryCharge;
  String finalPrice;



  @override
  RequestCheckOut fromMap(dynamic dynamicData) {
    if (dynamicData != null) {
      return RequestCheckOut(
        cartList : dynamicData['cartList'],
        paymentId : dynamicData['payment_id'],
        price : dynamicData['price'],
        deliveryAddressId : dynamicData['delivery_address_id'],
        billingAddressId : dynamicData['billing_address_id'],
        discount : dynamicData['discount'],
        deliveryCharge : dynamicData['delivery_charge_amt'],
        finalPrice : dynamicData['final_price'],


      );
    }
    else
    {
      return null;
    }
  }

  @override
  Map<String, dynamic> toMap()
  {
    var data = Map<String, dynamic>();

    data['cartList']=cartList;
    data['payment_id']=paymentId;
    data['price']=price;
    data['delivery_address_id']=deliveryAddressId;
    data['billing_address_id']=billingAddressId;
    data['discount']=discount;
    data['delivery_charge_amt']=deliveryCharge;
    data['final_price']=finalPrice;


    return data;
  }

  RequestCheckOut.fromJson(Map<String, dynamic> json) {

    cartList = (json['cartList']);
    paymentId = (json['payment_id']);
    price = (json['price']);
    deliveryAddressId = (json['delivery_address_id']);
    billingAddressId = (json['billing_address_id']);
    discount = (json['discount']);
    deliveryCharge = (json['delivery_charge_amt']);
    finalPrice = (json['final_price']);

  }
}

I have called the presenter from the view as follows:

  RequestCheckOut requestCheckout = RequestCheckOut(
                          cartList:widget.cartList,
                          paymentId: presenter.responsePayment.value.data
                              .paymentMethod[_value].id
                              .toString(),
                          price: widget.totalPrice.toString(),
                          deliveryAddressId: presenter.responseAddress.value
                              .data.addressList[toggleIndex].id
                              .toString(),
                          billingAddressId: presenter.responseAddress.value.data
                              .addressList[toggleIndex].id
                              .toString(),
                          discount: "0",
                          deliveryCharge: widget.shipPrice.toString(),
                          finalPrice: widget.totalPrice.toString(),
                        );
                     
                        presenter.doAddOrderApiCall(requestCheckout);

I have implemented doAddOrderApiCall in presenter as follows:

  doAddOrderApiCall(RequestCheckOut requestCheckOut) async
  {

    print("Do Add Order");
    view.showProgress();
    if (isConnectedToInternet)
    {
      print(requestCheckOut);
      final ResponseFormat<ResponseAddOrder> responseFormat = await contentRepo.doAddOrderApiCall(requestCheckOut.toMap());

      if(responseFormat.value.status)
      {

        view.hideProgress();
        view.showMessage(responseFormat.value.message);

        view.onBackPressed();

      }
      else
      {
        view.showMessage(responseFormat.value.message);
        view.hideProgress();
      }
    }
    else
    {

      view.hideProgress();
    }
  }

Response CartList

class ResponseCartList  extends ResponseUni<ResponseCartList>{
  bool status;
  String message;
  Data data;

  ResponseCartList({this.status, this.message, this.data});

  ResponseCartList.fromJson(Map<String, dynamic> json) {
    status = json['status'];
    message = json['message'];
    data = json['data'] != null ? new Data.fromJson(json['data']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['status'] = this.status;
    data['message'] = this.message;
    if (this.data != null) {
      data['data'] = this.data.toJson();
    }
    return data;
  }

  @override
  fromMap(dynamicData) {
    if (dynamicData != null)
    {
      return ResponseCartList(
        status: dynamicData['status'],
        message: dynamicData['message'],
        data:dynamicData['data']!=null?Data.fromJson(dynamicData['data']):null,
      );
    }
    else
    {
      return null;
    }
  }

  @override
  String getPrimaryKey() {
   return '';
  }

  @override
  Map<String, dynamic> toMap(object) {
    {
      if (object != null)
      {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['status'] = object.status;
        data['message'] = object.message;
        data['data'] = object.data!=null?object.data.toJson():null;
        return data;
      }
      else
      {
        return null;
      }
    }
  }
}

class Data {
  List<CartList> cartList;

  Data({this.cartList});

  Data.fromJson(Map<String, dynamic> json) {
    if (json['cart_list'] != null) {
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
try {
  final response = await http
      .post(
    '$url',
    headers: requestHeaders,
    body: valueMap,
  ).catchError((dynamic e) { /// <-- somehting wrong happened here and is catched
  
    print("${e.toString()}");
  });

when sending the http request there is some error with the parsing, so its catched with the catchError and you print the error which is:

type 'List<dynamic>' is not a subtype of type 'String' in type cast

Because of that the response it's null, that's why printing result returns null, and after that when calling final ResponseApi psApiResponse = ResponseApi(response); the first line:

code = response.statusCode;

throws the rest of your error, because response is null and cannot call statusCode from a null object

E/flutter (13443): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The getter 'statusCode' was called on null.
E/flutter (13443): Receiver: null
E/flutter (13443): Tried calling: statusCode
.....

I'm still confident that your error (which is some kind of parsing) is related with your cartList, you declared it as var cartList and the json.decode / encode tries to parse it as it understands it, if your cartList is a List but you declared it as var it will just assume its a List, you need to change it to the correct type so the decoder/encoder use the correct toJson/fromJson

class RequestCheckOut extends RequestUni<RequestCheckOut> {
  RequestCheckOut({

    this.cartList,
    this.paymentId,
    this.price,
    this.deliveryAddressId,
    this.billingAddressId,
    this.discount,
    this.deliveryCharge,
    this.finalPrice,

  });
  Data cartList;  // <---- Here use exactly the type of object you want to be encoded, Data, List<CartList> or ResponseCartList
  String paymentId;
  String price;
  String deliveryAddressId;
  String billingAddressId;
  String discount;
  String deliveryCharge;
  String finalPrice;



  @override
  RequestCheckOut fromMap(dynamic dynamicData) {
    if (dynamicData != null) {
      return RequestCheckOut(
        cartList : dynamicData['cartList'], // <--- Here try to use the correct fromJson/ fromMap instead of let the machine try it to guess it for you, because it will just decode it from the simplest objects, String, num, etc., if it's Data then use Data.fromJson(dynamicData['cartList'])
        paymentId : dynamicData['payment_id'],
        price : dynamicData['price'],
        deliveryAddressId : dynamicData['delivery_address_id'],
        billingAddressId : dynamicData['billing_address_id'],
        discount : dynamicData['discount'],
        deliveryCharge : dynamicData['delivery_charge_amt'],
        finalPrice : dynamicData['final_price'],


      );
    }
    else
    {
      return null;
    }
  }

  @override
  Map<String, dynamic> toMap()
  {
    var data = Map<String, dynamic>();

    data['cartList']=cartList;
    data['payment_id']=paymentId;
    data['price']=price;
    data['delivery_address_id']=deliveryAddressId;
    data['billing_address_id']=billingAddressId;
    data['discount']=discount;
    data['delivery_charge_amt']=deliveryCharge;
    data['final_price']=finalPrice;


    return data;
  }

  RequestCheckOut.fromJson(Map<String, dynamic> json) {

    cartList = (json['cartList']);
    paymentId = (json['payment_id']);
    price = (json['price']);
    deliveryAddressId = (json['delivery_address_id']);
    billingAddressId = (json['billing_address_id']);
    discount = (json['discount']);
    deliveryCharge = (json['delivery_charge_amt']);
    finalPrice = (json['final_price']);

  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...