Ложный тип при возврате данных из future из-за синтаксического анализа вложенной структуры с помощью списка

#java #flutter #future #flutter-futurebuilder

#java #флаттер #будущее #flutter-futurebuilder

Вопрос:

Я новичок в flutter и имею опыт работы только с PHP, поэтому вы можете счесть мои вопросы бессмысленными. Если да, пожалуйста, объясните мне, в чем я ошибаюсь, спасибо. Я использую два проекта в качестве источника для своего проекта: https://github.com/abdl-slm/FlutterGridFutureExample и https://github.com/PoojaB26/ParsingJSON-Flutter .

Я пытаюсь изменить данные get из API с помощью Future builder и grid_view, но я получаю это сообщение, когда пытаюсь вернуть список из future:

Значение типа ‘ActionsList’ не может быть возвращено из функции ‘getActions’, поскольку оно имеет возвращаемый тип ‘Future<Список>’.

Я проверил, что нет проблем с анализом данных в ActionsList (я могу распечатать их внутри future), но я не могу передать их остальной части futurebuilder.

Будущее выглядит следующим образом:

 Future<List<ActionsList>> getActions() async {
  final response = await http.get(
    "https://www.myproject.cz/api/...",
    headers: {
      "contentType": "application/x-www-form-urlencoded",
      "Authorization": "Bearer ...",
    },
  );

  if (response.statusCode == 200) {
    Map<String, dynamic> decodedActions = json.decode(response.body);
    String encodedActions = jsonEncode(decodedActions['actions_data']);

    final jsonResponse = json.decode(encodedActions);
    ActionsList actionsList = ActionsList.fromJson(jsonResponse);

    print("got data from API check: "   actionsList.actions[0].name);

    return actionsList;

  } else {
    throw Exception('Failed to load actions');
  }
}
 

JSON из API:

 {
  "actions_data": [
    {
      "id": "245629634987701888",
      "shop_id": "182980954485185472",
      "name": "Slevový kupón 10 % na techniku na FotoŠkoda",
      "valid_from": "2020-11-08T00:00:00 00:00",
      "valid_to": null,
      "description": "",
      "type": "coupon",
      "other_type": null,
      "discount": "10",
      "discount_type": "%",
      "discount_coupon": "POH10",
      "image_mobile_url": null,
      "aggregator": "affiliate_port",
      "redirect_link": "https://project.cz/aff_c?offer_id=234amp;aff_id=5921amp;aff_sub=107553508877665280"
    },
    {
      "id": "245628934350208704",
      "shop_id": "180719630782866560",
      "name": "Slevový kupon 200 Kč na dioptrické brýle na Alensa",
      "valid_from": "2020-11-08T00:00:00 00:00",
      "valid_to": null,
      "description": "",
      "type": "coupon",
      "other_type": null,
      "discount": "200",
      "discount_type": "CZK",
      "discount_coupon": "dioptricke200",
      "image_mobile_url": null,
      "aggregator": "ehub",
      "redirect_link": "https://project.cz/click.php?a_aid=bb9f4d85amp;a_bid=acf4b661amp;data1=107553508877665280"
    },
    {
      "id": "243716688296602880",
      "shop_id": "194864134897055232",
      "name": "Sleva na nábytek až 20%",
      "valid_from": "2020-11-03T00:00:00 00:00",
      "valid_to": null,
      "description": "",
      "type": "coupon",
      "other_type": null,
      "discount": "10",
      "discount_type": "%",
      "discount_coupon": "20AUTUMN",
      "image_mobile_url": "https://www.project.cz/actions-images/243716688296602880-mobile-699018679.png",
      "aggregator": "dognet",
      "redirect_link": "http://www.project.cz/sd?data1=107553508877665280"
    },...
 

Класс ActionList для сопоставления данных:

 import 'dart:convert';

class ActionsList {
  final List<ActionsData> actions;

  ActionsList({
    this.actions,
  });

  factory ActionsList.fromJson(List<dynamic> parsedJson) {

    List<ActionsData> actions = new List<ActionsData>();
    actions = parsedJson.map((i)=>ActionsData.fromJson(i)).toList();

    return new ActionsList(
        actions: actions
    );
  }
}


class ActionsData {
  final String id;
  final String shopId;
  final String name;
  final String validFrom;
  final String validTo;
  final String description;
  final String type;
  final String otherType;
  final String discount;
  final String discountType;
  final String discountCoupon;
  final String imageMobileUrl;
  final String aggregator;
  final String redirectLink;

  ActionsData(
      {this.id,
        this.shopId,
        this.name,
        this.validFrom,
        this.validTo,
        this.description,
        this.type,
        this.otherType,
        this.discount,
        this.discountType,
        this.discountCoupon,
        this.imageMobileUrl,
        this.aggregator,
        this.redirectLink});

  Map<String, dynamic> toJson(){
    return {
    "id": this.id,
    "shopId": this.shopId,
    "name": this.name,
    "validFrom": this.validFrom,
    "validTo": this.validTo,
    "description": this.description,
    "type": this.type,
    "otherType": this.otherType,
    "discount": this.discount,
    "discountType": this.discountType,
    "discountCoupon": this.discountCoupon,
    "imageMobileUrl": this.imageMobileUrl,
    "aggregator": this.aggregator,
    "redirectLink": this.redirectLink
    };
  }

  factory ActionsData.fromJson(Map<String, dynamic> json){
    return new ActionsData(
        id: json['id'],
        shopId: json['shop_id'],
        name: json['name'],
        validFrom: json['valid_from'],
        validTo: json['valid_to'],
        description: json['description'],
        type: json['type'],
        otherType: json['other_type'],
        discount: json['discount'],
        discountType: json['discount_type'],
        discountCoupon: json['discount_coupon'],
        imageMobileUrl: json['image_mobile_url'],
        aggregator: json['aggregator'],
        redirectLink: json['redirect_link']);
  }
}
 

И остальная часть главного экрана:

 class ThirdScreen extends StatefulWidget {
  ThirdScreen({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _ThirdScreenState createState() => _ThirdScreenState();
}

class _ThirdScreenState extends State<ThirdScreen> with TickerProviderStateMixin {

  Future<List<ActionsList>> futureAction;


  @override
  void initState() {
    super.initState();
   futureAction = getActions();

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        titleSpacing: 0.0,
        title: IconButton(
          icon: Icon(
            Icons.shopping_cart,
          ),
          onPressed: () {},
        ),
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.menu,
            ),
            onPressed: () {},
          )
        ],
      ),
      body: Center(
          child: FutureBuilder<List<ActionsList>>(
        future: futureAction,
        builder: (context, AsyncSnapshot snapshot) {
          if (!snapshot.hasData) {
            print("snapshot doesn't have data");
            return Center(child: CircularProgressIndicator());
          } else {
           // print(snapshot.data);
            return Container(child: _albumGridView(snapshot.data));
          }
        },
      )),
    );
  }
}

 

Спасибо за любые подсказки или примеры!

Ответ №1:

ваш метод Future ничего не вернет, если вы не вернете значение вне оператора else if . измените свой код на:

 Future<List<ActionsList>> getActions() async {
ActionsList actionsList;
  final response = await http.get(
    "https://www.myproject.cz/api/...",
    headers: {
      "contentType": "application/x-www-form-urlencoded",
      "Authorization": "Bearer ...",
    },
  );

  if (response.statusCode == 200) {
    Map<String, dynamic> decodedActions = json.decode(response.body);
    String encodedActions = jsonEncode(decodedActions['actions_data']);

    final jsonResponse = json.decode(encodedActions);
    actionsList = ActionsList.fromJson(jsonResponse);

    print("got data from API check: "   actionsList.actions[0].name);

  } else {
    throw Exception('Failed to load actions');
  }
return actionsList;
}
 

надеюсь, это сработает для вас.

Комментарии:

1. Спасибо, но проблема в другом — согласно Android Studio, я не использую правильный тип списка действий.. смотрите: ctrlv.cz/VQgf

Ответ №2:

 Future<ActionsList>() async {
  final response = await http.get(
    "https://www.myproject.cz/api/...",
    headers: {
      "contentType": "application/x-www-form-urlencoded",
      "Authorization": "Bearer ...",
    },
  );

  if (response.statusCode == 200) {
    Map<String, dynamic> decodedActions = json.decode(response.body);
    String encodedActions = jsonEncode(decodedActions['actions_data']);

    final jsonResponse = json.decode(encodedActions);
    ActionsList actionsList = ActionsList.fromJson(jsonResponse);

    print("got data from API check: "   actionsList.actions[0].name);

    return actionsList;

  } else {
    throw Exception('Failed to load actions');
  }
}
 

измените возвращаемый тип вашей функции с «Future<Список<Список действий>>» на «Future<Список действий>», и это решит вашу проблему.

Комментарии:

1. Привет, Захид, спасибо за вашу попытку, но при возврате списка действий все еще наблюдается несоответствие типов. Я думаю, что проблема в том, что JSON не прост, и мне нужно разобрать его по шагам … первый уровень как ActionList, а второй как ActionData … и я не уверен, как это сделать, используя future…