Flutter — 简单使用请求 Dio

Flutter — 简单使用请求 Dio


flutter dio 网络请求 移动端

1.post 请求

import 'package:dio/dio.dart';

import 'dart:convert' as JSON;
void main() async{

//  Future getData() {
//    String url = "https://xxxxxxx";
//    var map = {

//    };
//
//    print("开始请求数据");
//    return Dio().post(url, data: map);
//
//  }

//  getData().then((responseBody){
//    print(responseBody);
//  });



  post(String url,Map data){
    return Dio().post(url, data: data,options: Options(headers:{"Content-Type":'application/json'}));
  }

  String url = "https://xxxxxxx";
  var map = {

  };
  var res = await post(url, map);
  print(res);

}

2.通过请求来的数据实现简单列表

import 'package:flutter/material.dart';

import 'package:dio/dio.dart';

import 'dart:convert' as JSON;

void main()async{

  post(String url,Map data){
    return Dio().post(url, data: data,options: Options(headers:{"Content-Type":'application/json'}));
  }

  String url = "https://xxxxxx";
  var map = {

  };
  var res = await post(url, map);
  Map result = JSON.jsonDecode(res.toString());

  runApp(MyApp(
      result['content']
  ));
}

class MyApp extends StatelessWidget {

  final List items;
  MyApp(this.items);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title:'Title',
        home:Scaffold(
            appBar: AppBar(title:Text('Hello')),
            body:ListView.builder(
              itemCount: items.length,
              itemBuilder: (context,index){
                return Column(
                    children: <Widget>[
                      ListTile(title: Text(items[index]['title'])),
                      Image.network(
                        items[index]['homepageId'] + '?x-oss-process=style/w800',
                        width: 200,
                        height:100,
                        fit:BoxFit.cover,
//                        color:Colors.pink,
//                        colorBlendMode: BlendMode.modulate,
                      ),

                    ],
                );
              },
            )
        )
    );
  }
}

3.有状态无状态

statelessWidget

Stateless widgets 无状态控件是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的. 如 app 入口 runApp 的 widget

使用时继承 StatelessWidget

statefullWidget

Stateful widgets 有状态控件。持有的状态可在 widget 生命周期中发生变化实现一个 stateful widget 至少需要两个类。

  • 1.一个 StatefulWidget 类
  • 2.一个 State 类。 StatefulWidget 类本身是不变的,但是 State 类在 widget 生命周期中始终存在,且可改变

实现方式:

  • 1.自定义一个类继承自 statefulWidget
  • 2.重写 createState()方法,为该 statefulWidget 创建一个 state 对象
  • 3.自定义一个状态类继承自 State,重写 build()方法,根据需要的逻辑处理返回 widget,build 方法会在 view 状态改变时进行回调,重新渲染(自动响应式框架)

widget 更新

widget 只支持一帧,每一帧都会重新绘制 widget 实例,相当于一次绘制整个界面,widget 本身都不可变,想要可变就需要控制状态,无状态和有状态 widget 的核心特性是相同的。每一帧它们都会重新构建,不同之处在于 StatefulWidget 有一个 State 对象,它可以跨帧存储状态数据并恢复它。可交互就是有状态的,stateless 中可以包含 stateful。

下拉加载

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert' as JSON;

void main() async {
  runApp(MyApp());
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue
      ),
      home:MyHomePage()
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  int page = 1;

  List cases;

  bool loading = false;

  @override
  Widget build(BuildContext context) {
    var length = cases?.length ?? 0;
    return Scaffold(
      body: ListView.builder(
          itemBuilder: (context,index){
            print('$index @@@');
            if(index == length){
              load();
              return new Center(
                child: new Container(
                  margin: const EdgeInsets.only(top: 8.0),
                  width: 32.0,
                  height: 32.0,
                  child: const CircularProgressIndicator(),
                ),
              );
            } else if (index > length) {
                return null;
            }
            return Column(
                children: <Widget>[
                  ListTile(title: Text(cases[index]['title'])),
                  Image.network(
                    cases[index]['homepageId'] + '?x-oss-process=style/w800',
            )]);
      }),
    );
  }


  Future load() async {
    if (loading) {
      return null;
    }
    loading = true;
    try {
      var url = "https://admin.atjia.com//api_cms/front/busiContentCaseFront/queryByParmsPC";
      var map = {
        "export": false,
        "orderBy": "ups desc,rank asc,modify_time desc",
        "page": page,
        "pageSize": 10,
        "queryParamList": [
          {
            "field": "searchKey",
            "type": "string",
            "logic": "like",
            "value": "",
            "items": []
          },
          {
            "field": "designerId",
            "items": [],
            "logic": "",
            "type": "",
            "value": ""
          },
          {
            "field": "caseType",
            "type": "string",
            "logic": "=",
            "value": "1",
            "items": []
          }
        ]
      };
      var res = await post(url, map);
      Map result = JSON.jsonDecode(res.toString());
      var content = result['content'];
      setState(() {
        page += 1;
        if (content is List) {
          if (cases == null) {
            cases = <Map>[];
          }
        cases = [...cases,...content];
        }
      });
    } finally {
      loading = false;
    }
  }

  post(String url, Map data) {
    return Dio().post(url,
        data: data,
        options: Options(headers: {"Content-Type": 'application/json'}));
  }

}

在构建 ListView 时有 4 中选择:

  1. 利用显示的自列表来构造 List。此构造函数适合于具有少量子元素的列表视图,因为构造列表需要为可能显示在列表视图中的每个子元素执行工作,而不仅仅是那些实际可见的子元素。

  2. ListView.builder 利用 IndexedWidgetBuilder 来按需构造。这个构造函数适合于具有大量(或无限)子视图的列表视图,因为构建器只对那些实际可见的子视图调用。

  3. 使用 ListView.separated 构造函数,采用两个 IndexedWidgetBuilder:itemBuilder 根据需要构建子项 separatorBuilder 类似地构建出现在子项之间的分隔符子项。此构造函数适用于具有固定数量的子控件的列表视图。

  4. 使用 ListView.custom 的 SliverChildDelegate 构造,它提供了定制子模型的其他方面的能力。 例如,SliverChildDelegate 可以控制用于估计实际上不可见的孩子的大小的算法。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'List Demo',
      home:Scaffold(
        body: new ListView.separated(
        itemBuilder: (BuildContext context, int index) {
            return new Text("text $index");
        },
        separatorBuilder: (BuildContext context, int index) {
            return new Container(height: 1.0, color: Colors.red);
        },
        itemCount: 40),
      )
    );
  }
}

加一个点击事件

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert' as JSON;

void main() async {
  runApp(MyApp());
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: 'List Demo',
      home:MyHomePage()
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  int page = 1;

  List cases;

  bool loading = false;

  @override

  Widget build(BuildContext context) {
    var length = cases?.length ?? 0;
    return Scaffold(
      body: ListView.builder(
          itemBuilder: (context,index){
            print('$index @@@');
            if(index == length){
              load();
              return new Center(
                child: new Container(
                  margin: const EdgeInsets.only(top: 8.0),
                  width: 32.0,
                  height: 32.0,
                  child: const CircularProgressIndicator(),
                ),
              );
            } else if (index > length) {
                return null;
            }
            return Column(
                children: <Widget>[
                  ListTile(
                      title: Text(cases[index]['title']),
                      onTap: () {
                        showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return new AlertDialog(
                              title: new Text(
                                '测试',
                                style: new TextStyle(
                                  color: Colors.black54,
                                  fontSize: 18.0,
                                ),
                              ),
                              content: new Text('您选择的标题为:${cases[index]['title']}'),
                            );
                          },
                        );
                      }
                  ),
                  Image.network(
                    cases[index]['homepageId'] + '?x-oss-process=style/w800',
                  )
                ],

            );
      }),
    );
  }

  Future load() async {
    if (loading) {
      return null;
    }
    loading = true;
    try {
      var url = "https://admin.atjia.com//api_cms/front/busiContentCaseFront/queryByParmsPC";
      var map = {
        "export": false,
        "orderBy": "ups desc,rank asc,modify_time desc",
        "page": page,
        "pageSize": 10,
        "queryParamList": [
          {
            "field": "searchKey",
            "type": "string",
            "logic": "like",
            "value": "",
            "items": []
          },
          {
            "field": "designerId",
            "items": [],
            "logic": "",
            "type": "",
            "value": ""
          },
          {
            "field": "caseType",
            "type": "string",
            "logic": "=",
            "value": "1",
            "items": []
          }
        ]
      };
      var res = await post(url, map);
      Map result = JSON.jsonDecode(res.toString());
      var content = result['content'];
      setState(() {
        page += 1;
        if (content is List) {
          if (cases == null) {
            cases = <Map>[];
          }
        cases = [...cases,...content];
        }
      });
    } finally {
      loading = false;
    }
  }

  post(String url, Map data) {
    return Dio().post(url,
        data: data,
        options: Options(headers: {"Content-Type": 'application/json'}));
  }


}

© 2025 Niko Xie