Flutter网络请求,解析json数据,列表展示

实现效果:


image

需要使用到的第三方网络库:dio

在pubspec.yaml中添加第三方库(相当于Android Studio中的build gradle目录)
dio: ^0.0.14 (dio第三方库名,^后面代表版本号,点击packages get后完成依赖)

使用干货提供的JSON数据。
http://gank.io/api/data/

json格式如下:
{
"error": false,
"results": [
{
"_id": "5b3d883f421aa906e5b3c6f1",
"createdAt": "2018-07-05T10:53:51.361Z",
"desc": "2018-07-05",
"publishedAt": "2018-07-05T00:00:00.0Z",
"source": "web",
"type": "\u798f\u5229",
"url": "http://ww1.sinaimg.cn/large/0065oQSqly1fsysqszneoj30hi0pvqb7.jpg",
"used": true,
"who": "lijinshanmx"
}
]
}

第一步:

建立JSON所对应得model类,解析过程在FLModel.formJson()中处理,对应key即可解析,这里注意类型必须对应,否则解析失败,比如返回String类型,你声明时却是int,这里不会自动转换,导致数据无法解析出来。

/解析类

  class FLModle{
     final String _id;
      final String createdAt;
    final String desc;
    final String publishedAt;
    final String source;
    final String type;
    final String url;
    final bool used;
    final String who;

    const FLModle(this._id, this.createdAt, this.desc, this.publishedAt, this.source,
    this.type, this.url, this.used, this.who);

@override
  String toString() {
    return 'FLModle{_id: $_id, createdAt: $createdAt, desc: $desc, publishedAt: $publishedAt, source: $source, type: $type, url:           $url, used: $used, who: $who}';
  }

    FLModle.fromJson(Map<String, dynamic> json)
    : _id = json['_id'],
    createdAt = json['createdAt'],
    desc = json['desc'],
    publishedAt = json['publishedAt'],
    source = json['source'],
    type = json['publishedAt'],
    url = json['url'],
    used = json['used'],
    who = json['who'];
  }

第二步:

创建一个有状态的组件,继承StatefulWidget,在createState方法中创建我们继承State的组件。

class MeziList extends StatefulWidget{
      @override
      State<StatefulWidget> createState() {
        // TODO: implement createState
        return new MeziSateList();
  }
}

第三步:创建MeziSateList,继承State组件,可通过setState来更新UI,相当于Android中的runOnUI
(此处内代码放在最后一步编写)。

class MeziSateList extends State<MeziList>{
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        }
      }

第四步:

构建网络请求,返回需要的List集合,使用async和await来完成耗时的操作,相当关android中的子线程,Future类似于消息机制(个人观点,只是为了简单理解):

          Future<List<FLModle>>  _getDate(int pageNum,int pageSize) async{
        List flModels;
        String url = Constant.baseUrl + '福利/$pageSize/$pageNum';
        print(url);
          Response response = await dio.get(url);
          if(response.statusCode== HttpStatus.OK){//响应成功
              flModels = (response.data)['results'] ;
              currentpage = currentpage+1;//加载成功后才可加载下一页
          }else{//出问题
         }
        print(flModels.map((model) {
          return new FLModle.fromJson(model);
        }).toList().length);

        return flModels.map((model) {
          return new FLModle.fromJson(model);
      }).toList();

          }


  Future<List<FLModle>> feach(int pageNum,int pageSize){
return _getDate(pageNum, pageSize);
  }

第四步:编写加载更多和刷新各自对应的逻辑

//刷新时调用

  Future<Null> _refreshData(){

final Completer<Null> completer = new Completer<Null>();
currentpage = 1;
feach(currentpage, pageSize).then((list) {
  setState(() {
      datas = list;
  });
}).catchError((error) {
  print(error);
});
completer.complete(null);
return completer.future;
  }

//加载更多时调用

  Future<Null> _loadMoreData(){

final Completer<Null> completer = new Completer<Null>();


feach(currentpage, pageSize).then((list) {
  setState(() {
      datas.addAll(list);
  });
}).catchError((error) {
  print(error);
});
completer.complete(null);

return completer.future;
  }

第五步:

创建ScrollController来监听ListView的滑动,需要在initState方法中addListener,并且在dispose中removeListener。

/滑动到底了自动加载更多

  void _scrollListener(){
if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){
  _loadMoreData();
}
  }

//页面初始化时加载数据并实例化ScrollController

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _refreshData();
    _scrollController = new ScrollController()..addListener(_scrollListener);
  }

   @override
    void dispose() {
      // TODO: implement dispose
    super.dispose();
    _scrollController.removeListener(_scrollListener);
  }

第六步:

创建item并实现点击事件

Widget buildCardItem(BuildContext context,int index){
    final String url = datas[index].url;
    return new GestureDetector(//点击事件
      onTap: (){

       _showPhoto(url);
      },
      child: new Card(
        child: new Container(
          padding: EdgeInsets.all(8.0),
          child: new Image.network(url),
        ),
      ),
    );
  }

最后一步:

构建ListView,数据加载时显示圆环

 @override
  Widget build(BuildContext context) {
    // TODO: implement build
    var content ;
    if(datas.isEmpty){
      content =  new Center(child: new CircularProgressIndicator());;
    }else{
      content = new ListView.builder(
        physics: AlwaysScrollableScrollPhysics(),
        itemCount: datas.length,
        controller: _scrollController,
        itemBuilder: buildCardItem,
      );
    }

    var _refreshIndicator = new RefreshIndicator(
        onRefresh: _refreshData,
      child: content,
    );
    return _refreshIndicator;
  }

完整代码

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'progreess_dialog.dart';
import 'package:easy_app/multi_touch_page.dart';
import 'constant.dart';
//解析类

class FLModle{
  final String _id;
  final String createdAt;
  final String desc;
  final String publishedAt;
  final String source;
  final String type;
  final String url;
  final bool used;
  final String who;

  const FLModle(this._id, this.createdAt, this.desc, this.publishedAt, this.source,
      this.type, this.url, this.used, this.who);

  @override
  String toString() {
    return 'FLModle{_id: $_id, createdAt: $createdAt, desc: $desc, publishedAt: $publishedAt, source: $source, type: $type, url: $url, used: $used, who: $who}';
  }

  FLModle.fromJson(Map<String, dynamic> json)
  : _id = json['_id'],
    createdAt = json['createdAt'],
    desc = json['desc'],
    publishedAt = json['publishedAt'],
    source = json['source'],
    type = json['publishedAt'],
    url = json['url'],
    used = json['used'],
    who = json['who'];
}

class TabGirlPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
// TODO: implement build
    return new Scaffold(
     body: new MeziList(),
    );
  }

}

class MeziList extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new MeziSateList();
  }
}

class MeziSateList extends State<MeziList>{

  List<FLModle> datas = [];//初始化列表数据源
  int currentpage = 1;//默认当前页
  int pageSize = 10;//每页加载数据


  Dio dio = new Dio();//第三方网络加载库
  ScrollController _scrollController;

  //滑动到底了自动加载更多
  void _scrollListener(){
    if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){
      _loadMoreData();
    }
  }

//页面初始化时加载数据并实例化ScrollController
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _refreshData();
    _scrollController = new ScrollController()..addListener(_scrollListener);
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.removeListener(_scrollListener);
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    var content ;
    if(datas.isEmpty){
      content =  new Center(child: new CircularProgressIndicator());;
    }else{
      content = new ListView.builder(
        physics: AlwaysScrollableScrollPhysics(),
        itemCount: datas.length,
        controller: _scrollController,
        itemBuilder: buildCardItem,
      );
   }  

    var _refreshIndicator = new RefreshIndicator(
        onRefresh: _refreshData,
      child: content,
    );
    return _refreshIndicator;
  }

  void _showPhoto(String url) {
    Navigator.of(context).push(new PageRouteBuilder(
        opaque: false,
        pageBuilder: (BuildContext context, _, __) {
          return new MultiTouchPage(url);
        },
        transitionsBuilder: (_, Animation<double> animation, __, Widget child) {
          return new FadeTransition(
            opacity: animation,
            child: new RotationTransition(
              turns: new Tween<double>(begin: 0.5, end: 1.0).animate(animation),
              child: child,
            ),
          );
        }));
  }

  Widget buildCardItem(BuildContext context,int index){
    final String url = datas[index].url;
   return new GestureDetector(//点击事件
      onTap: (){
     
        _showPhoto(url);
      },
        child: new Card(
        child: new Container(
          padding: EdgeInsets.all(8.0),
          child: new Image.network(url),
        ),
      ),
    );
  }

  //刷新时调用
      Future<Null> _refreshData(){

    final Completer<Null> completer = new Completer<Null>();
    currentpage = 1;
    feach(currentpage, pageSize).then((list) {
      setState(() {
          datas = list;
      });
    }).catchError((error) {
      print(error);
    });
    completer.complete(null);
    eturn completer.future;
  }

  //加载更多时调用
  Future<Null> _loadMoreData(){

    final Completer<Null> completer = new Completer<Null>();


    feach(currentpage, pageSize).then((list) {
      setState(() {
          datas.addAll(list);
      });
    }).catchError((error) {
      print(error);
    });
    completer.complete(null);

    return completer.future;
  }

  Future<List<FLModle>> feach(int pageNum,int pageSize){
   return _getDate(pageNum, pageSize);
  }

  Future<List<FLModle>>  _getDate(int pageNum,int pageSize) async{
    List flModels;
    String url = Constant.baseUrl + '福利/$pageSize/$pageNum';
    print(url);
      Response response = await dio.get(url);
      if(response.statusCode== HttpStatus.OK){//响应成功
          flModels = (response.data)['results'] ;
          currentpage = currentpage+1;//加载成功后才可加载下一页
      }else{//出问题
      }
    print(flModels.map((model) {
      return new FLModle.fromJson(model);
    }).toList().length);

    return flModels.map((model) {
      return new FLModle.fromJson(model);
    }).toList();

  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容