“flutter”数据model及json处理
Nealyang opened this issue · 3 comments
前言
由于我们最终是需要通过接口获取数据的,笔者个人习惯,比较喜欢先确认了字段再去进行代码的编写,所以这一章节,我们先mock下接口的数据。
从Chrome中,我copy了一份请求:list api
我们将数据copy一份到本地json中
在项目的根目录下新建一个 assets 文件夹,用于存放我们的json
- assets/indexListData.json
内容较长,这里就不粘贴了。大家可以直接copy我的文件,也可以直接copy请求过来的数据
因为是资源文件的注入,所以我们需要在pubspec.yaml
中注册一下
assets:
- assets/indexListData.json
listCell数据模型
原始数据我们有了,根据UI,我们肯定需要将list的每一个cell拆出来作为组件来使用的。
所以我们在lib目录下新建一个widgets
目录用于存放我们项目中需要自定的组件
我们来定义一个该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),
);
}
}
congratulation~ 成功了!
数据已经有了,下面就开始编写我们的这个indexListCell
widget吧!
总结
如上,我们完成了本地mock的数据,至此,你应该学会
- 定义和使用数据模型
- 异步获取本地mock data
我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'
我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'
数据转换类型错误了吧,可以 debugger 看下哪部分转换出错了
我这里提示 type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'IndexCell'
数据转换类型错误了吧,可以 debugger 看下哪部分转换出错了
应该是因为new Map()不能隐式转换成IndexCell的原因。
tags有时候会是空的,空的时候直接取值的话会throw,getIndexListData()好像会直接返回空对象