Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

“flutter”数据model及json处理 #21

Open
Nealyang opened this issue Mar 19, 2019 · 3 comments
Open

“flutter”数据model及json处理 #21

Nealyang opened this issue Mar 19, 2019 · 3 comments
Labels

Comments

@Nealyang
Copy link
Owner

前言

由于我们最终是需要通过接口获取数据的,笔者个人习惯,比较喜欢先确认了字段再去进行代码的编写,所以这一章节,我们先mock下接口的数据。

从Chrome中,我copy了一份请求:list api

我们将数据copy一份到本地json中

在项目的根目录下新建一个 assets 文件夹,用于存放我们的json

  • assets/indexListData.json

内容较长,这里就不粘贴了。大家可以直接copy我的文件,也可以直接copy请求过来的数据

json

因为是资源文件的注入,所以我们需要在pubspec.yaml中注册一下

  assets:
   - assets/indexListData.json

listCell数据模型

原始数据我们有了,根据UI,我们肯定需要将list的每一个cell拆出来作为组件来使用的。

所以我们在lib目录下新建一个widgets目录用于存放我们项目中需要自定的组件

分析cell的UI样式
cell

我们来定义一个该Cell需要的数据model!

在lib目录下新建model目录

  • lib/model/indexCell.dart
  import '../util/util.dart';
  
  class IndexCell {
    bool hot;
    String isCollection;
    String tag;
    String username;
    int collectionCount;
    int commentCount;
    String title;
    String createdTime;
    String detailUrl;
  
    IndexCell(
        {this.hot,
        this.tag,
        this.username,
        this.collectionCount,
        this.createdTime,
        this.commentCount,
        this.title,
        this.detailUrl,
        this.isCollection});
  
    factory IndexCell.fromJson(Map<String, dynamic> json) {
      return IndexCell(
        hot: json['hot'],
        collectionCount: json['collectionCount'],
        commentCount: json['commentsCount'],
        tag: json['tags'][0]['title'] + '/' + json['category']['name'],
        username: json['user']['username'],
        createdTime: Util.getTimeDuration(json['createdAt']),
        title: json['title'],
        detailUrl: json['originalUrl'],
        isCollection: json['type'] ,
      );
    }
  }

如上,我们就定义了一个包含一些字段的类,因为涉及使用量很大,我们使用一个工厂构造函数,为了方便传json,这里我们再定义了一个命名构造函数 IndexCell.fromJson,而里面是对接口字段的处理赋值操作。

因为是mock(接口)过来的数据,很多时候我们都要进行一些数据格式或者字段的处理,方便我们前端UI的展示,所以这里我们在lib目录下新建一个util目录

  • lib/util/util.dart
  class Util {
  
    static String getTimeDuration(String comTime) {
      var nowTime = DateTime.now();
      var compareTime = DateTime.parse(comTime);
      if (nowTime.isAfter(compareTime)) {
        if (nowTime.year == compareTime.year) {
          if (nowTime.month == compareTime.month) {
            if (nowTime.day == compareTime.day) {
              if (nowTime.hour == compareTime.hour) {
                if (nowTime.minute == compareTime.minute) {
                  return '片刻之间';
                }
                return (nowTime.minute - compareTime.minute).toString() + '分钟前';
              }
              return (nowTime.hour - compareTime.hour).toString() + '小时前';
            }
            return (nowTime.day - compareTime.day).toString() + '天前';
          }
          return (nowTime.month - compareTime.month).toString() + '月前';
        }
        return (nowTime.year - compareTime.year).toString() + '年前';
      }
      return 'time error';
    }
  }

上面代码写的有点呆呆的,后来我查了DateTime对象,可以使用difference方法来对比两个时间差,这里就不做修改了

我们如上定义了一个处理时间的方法,复制给cell

使用mock数据和数据model

这里说下笔者个人的代码习惯,如上代码,indexPage 是我们首页UI的容器,我只想在这里一个方法拿到我要的数据,然后丢给cell去渲染,就完事了,不希望有太多关于数据的逻辑处理

所以我们在lib/util下新建一个文件 dataUtils.dart文件,用于对请求过来数据的处理和封装

  • lib/util/dataUtils.dart
    引入基础库
  import 'dart:convert';
  import '../model/indexCell.dart';
  import 'package:flutter/services.dart' show rootBundle;
  import 'dart:async' show Future;

services、async 用于我们的数据请求,虽然是读取本地json但是熟悉node应该都明白,IO当然也是异步操作。

convert用于对json数据的处理,强烈推荐文章:[译]在 Flutter 中解析复杂的
JSON

引入数据model,方便处理和吐出。

  class DataUtils {
    static Future<String> _loadIndexListAsset() async {
      return await rootBundle.loadString('assets/indexListData.json');
    }
  
    static Future<List<IndexCell>> getIndexListData() async {
      List<IndexCell> resultList = new List();
      String jsonString = await _loadIndexListAsset();
      final jsonResponseList = json.decode(jsonString)['indexListData'];
      for(int i = 0;i<jsonResponseList.length;i++){
        // resultList.add();
        IndexCell cellData = new IndexCell.fromJson(jsonResponseList[i]);
        resultList.add(cellData);
      }
      return resultList;
    }
  }

关于上面的语法已在第一章节重点说明,这里不再赘述。
方法getIndexListData吐出List<IndexCell>

在IndexPage中,我们直接如下使用

  • lib/pages/indexPage.dart
  getList(bool isLoadMore) {
    DataUtils.getIndexListData().then((resultList) {
      setState(() {
        _listData = resultList;
      });
    });
  }

方法如上,调用时机这里我们方便测试,放到initState中,并将拿到的数据丢给我们的Cell widget来测试下,是否成功了(当然,使用print就可以),注意这里 传参:isLoadMore 是为了后面做加载更多的时候使用,这里我们重点在于mock data,所以先留下这个flag,暂时方法体里并未使用该变量。

  @override
  void initState() {
    super.initState();
    getList(false);
  }
  
    @override
  Widget build(BuildContext context) {
    print(_listData.length);
    return Column(
      children: <Widget>[
        Text('IndexPage'),
        IndexListCell(cellInfo: _listData.length>0?_listData[0]:new Map())
      ],
    );
  }

上面的三目运算看起来也是呆呆的哇,没有数据就不应该渲染IndexListCell嘛,但是这里我们先这样,后面我们会加loading

cell 中对于数据Model的使用

  • widgets/indexListCell.dart
  import 'package:flutter/material.dart';
  import '../model/indexCell.dart';
  
  class IndexListCell extends StatelessWidget {
    final IndexCell cellInfo;
  
    IndexListCell({Key key,this.cellInfo}):super(key : key);
  
    @override
    Widget build(BuildContext context) {
      return Container(
        child: Text(cellInfo.username),
      );
    }
  }

如上,此刻的你,应该看到如下界面:
data

congratulation~ 成功了!

数据已经有了,下面就开始编写我们的这个indexListCellwidget吧!

总结

如上,我们完成了本地mock的数据,至此,你应该学会

  • 定义和使用数据模型
  • 异步获取本地mock data
@JDChi
Copy link

JDChi commented Sep 17, 2019

我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'

@Nealyang
Copy link
Owner Author

我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'

数据转换类型错误了吧,可以 debugger 看下哪部分转换出错了

@Eoous
Copy link

Eoous commented Dec 30, 2019

我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'

数据转换类型错误了吧,可以 debugger 看下哪部分转换出错了

应该是因为new Map()不能隐式转换成IndexCell的原因。

tags有时候会是空的,空的时候直接取值的话会throw,getIndexListData()好像会直接返回空对象

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants