【问题标题】:How to parse nested json with FutureProvider in Flutter如何在 Flutter 中使用 FutureProvider 解析嵌套的 json
【发布时间】:2020-11-08 22:14:34
【问题描述】:

我正在尝试在我的应用程序中解析嵌套的 JSON 文档。 JSON 结构如下所示:

[
{
    "id": 1,
    "content": [
        {
            "type": "text",
            "value": "This is a Text1"
        },
        {
            "type": "latex",
            "value": "\frac00"
        },
        {
            "type": "text",
            "value": "This is a Text2"
        },
        {
            "type": "latex",
            "value": "\frac00"
        },
        {
            "type": "text",
            "value": "This is a Text3"
        }
    ]
},
{
    "id": 2,
    "content": [
        {
            "type": "text",
            "value": "This is a Text"
        }
    ]
}

] 这是我的模型类:

class Tutorial {
  String id;
  List<Content> content;

  Tutorial({this.id, this.content});

  Tutorial.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    if (json['content'] != null) {
      content = new List<Content>();
      json['content'].forEach((v) {
        content.add(new Content.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    if (this.content != null) {
      data['content'] = this.content.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Content {
  String type;
  String value;

  Content({this.type, this.value});

  Content.fromJson(Map<String, dynamic> json) {
    type = json['type'];
    value = json['value'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['type'] = this.type;
    data['value'] = this.value;
    return data;
  }
}

这就是我检索该 Json 并制作响应对象的方式:

import 'package:Mathzi/pages/courses/models/tutorialModel.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:async' show Future;
import 'dart:convert' as convert;

class TutorialService {
  Future<List> fetchTutorial() async {
    var response = await rootBundle.loadString('assets/tutorial.json');
    final jsonResponse = convert.jsonDecode(response) as List;
    return jsonResponse.map((tutorial) => Tutorial.fromJson(tutorial)).toList();
  }
}

这是我的屏幕小部件树:

  final TutorialService tutorialService = TutorialService();

  @override
  Widget build(BuildContext context) {
    return FutureProvider(
      create: (context) => tutorialService.fetchTutorial(),
      catchError: (context, error) => print(error.toString()),
      child: SizeTransition(
        axis: Axis.vertical,
        sizeFactor: animation,
        child: GestureDetector(
          //behavior: HitTestBehavior.opaque,
          onTap: onTap,
          child: SizedBox(
              height: 50.0,
              width: MediaQuery.of(context).size.width,
              child: TutParagraph()
              ),
        ),
      ),
    );
  }

还有我的 TutParagraph.dart:

import 'package:Mathzi/pages/courses/models/tutorialModel.dart';
import 'package:catex/catex.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'models/tutorialModel.dart';

class TutParagraph extends StatelessWidget {
  const TutParagraph({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Content> parag = Provider.of<List<Content>>(context);
    return (parag == null)
        ? Center(child: CircularProgressIndicator())
        : ListView.builder(
            itemCount: parag.length,
            itemBuilder: (context, index) {
              if (parag[index].type.toString() == "text")
                return Text(parag[index].value.toString());
              else if (parag[index].type.toString() == "latex")
                return CaTeX(parag[index].value.toString());
              else
                return null;
            },
          );
  }
}

如果类型等于 text 我使用 Text() 小部件来显示它,如果是 latex 我使用 CaTex()

当我运行我的代码时,它给了我这个错误信息:

错误:

在此上方找不到正确的 Provider TutParagraph 小部件

要修复,请:

  • 确保 Provider 是它的祖先 TutParagraph Widget * 向 Provider 提供类型 * 提供类型给消费者 * 提供类型给 Provider.of() * 确保正确的context 正在 用过。

【问题讨论】:

  • 尝试将类型赋予FutureProvider&lt;List&gt;,我也没有看到&lt;List&lt;Content&gt;&gt; 类型的提供者
  • @EdwynZN 我的 json 响应已经是一个列表。这里:return jsonResponse.map((tutorial) => Tutorial.fromJson(tutorial)).toList();这是我的 Content ,它是 Tutorial List parag = Provider.of>(context); 中的嵌套列表
  • 是的,我看到了,但是提供者只看到一个列表,不知道该列表的每个元素内都有一个嵌套的 Content 类型,所以你不能这样称呼它,@987654331 @ 不会给你任何错误,因为这是你从未来返回的正确类型的 List
  • 现在它给出了这个错误:错误:在这个 TutParagraph Widget 上方找不到正确的 Provider>

标签: flutter dart flutter-provider


【解决方案1】:

最好的解决方案是尝试强制转换并明确告知 List 使用的对象类型以避免此类问题,而不是让它推断它

class TutorialService {
  Future<List<Tutorial>> fetchTutorial() async {  //Tell the trturn type of the List
    var response = await rootBundle.loadString('assets/tutorial.json');
    final jsonResponse = convert.jsonDecode(response) as List;
    return jsonResponse.map<Tutorial>((tutorial) => Tutorial.fromJson(tutorial)).toList();
    //Cast the type in the map method <Tutorial>
  }
}

再次在 FutureProvider 中

FutureProvider<List<Tutorial>>( //perhaps it can infere it correctly now that the return type explicitly says is a List<Tutorial>, but lets add it anyway just in case
   create: (context) => tutorialService.fetchTutorial(),
   catchError: (context, error) => print(error.toString()),
   child: ...
)

在 TutParagraph 中

class TutParagraph extends StatelessWidget {
  const TutParagraph({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<Tutorial> tutorial = Provider.of<List<Tutorial>>(context); //it should find the FutureProvider
    List<Content> parag = (tutorial?.isEmpty ?? true) ? null : tutorial[0].content; //but this will only give you the list of the first element of the tutorial List
    return (parag == null)
        ? Center(child: CircularProgressIndicator())
        : ListView.builder(
            itemCount: parag.length,
            itemBuilder: (context, index) {
              if (parag[index].type.toString() == "text")
                return Text(parag[index].value.toString());
              else if (parag[index].type.toString() == "latex")
                return CaTeX(parag[index].value.toString());
              else
                return null;
            },
          );
  }
}

现在,如果您只想检索 List&lt;Content&gt;,您应该尝试更改 tutorialService.fetchTutorial() 的逻辑以仅返回该类型的列表,因为 Provider 不知道 Tutorial 中的类型,显然如果您有一个List&lt;Tutorial&gt; 它不知道你真正想要的教程列表的索引的List&lt;Content&gt;

【讨论】:

  • 现在,它给出了这个错误:(dirty, dependencies: [_InheritedProviderScope>]): NoSuchMethodError: invalid member on null: '_get' 相关的导致错误的小部件是:TutParagraph file:///Users/amin/FlutterProjects/mathzi/lib/pages/courses/tutorial l_page.dart:267:22
  • 那是因为列表还没有被检索到(Future还没有结束)所以它是null,在尝试使用它之前尝试检查一个mill值
猜你喜欢
  • 2020-09-24
  • 2021-02-25
  • 2019-10-06
  • 2019-01-24
  • 2019-12-30
  • 2021-02-09
  • 2020-05-21
  • 2023-04-02
  • 2018-07-12
相关资源
最近更新 更多