教程 > flutter 教程 > 阅读:119

flutter 访问 rest api——迹忆客-ag捕鱼王app官网

flutter 提供 http 包来消耗 http 资源。 http 是一个基于 future 的库,使用 await 和 async 特性。 它提供了许多高级方法并简化了基于 rest 的移动应用程序的开发。


基本概念

http 包提供了一个高级类和 http 来做 web 请求。

http 类提供了执行所有类型的 http 请求的功能。

http 方法通过 dart map 接受 url 和附加信息(发布数据、附加标头等)。 它请求服务器并以异步/等待模式收集响应。 例如,下面的代码从指定的 url 读取数据并在控制台中打印出来。

print(await http.read('https://flutter.dev/'));

一些核心方法如下 -

  • read - 通过 get 方法请求指定的 url 并将响应返回为 future
  • get - 通过 get 方法请求指定的 url,并将响应返回为 future。 response 是一个保存响应信息的类。
  • post - 通过发布提供的数据并通过 post 方法请求指定的 url 并将响应返回为 future
  • put - 通过 put 方法请求指定的 url 并将响应返回为 future
  • head - 通过 head 方法请求指定的 url 并将响应返回为 future
  • delete - 通过 delete 方法请求指定的 url,并将响应返回为 future

http 还提供了一个更标准的 http 客户端类 client。客户端支持持久连接。当向特定服务器发出大量请求时,它将很有用。它需要使用 close 方法正确关闭。否则,它类似于 http 类。示例代码如下

var client = new http.client(); 
try { 
   print(await client.get('https://flutter.dev/')); 
} 
finally { 
   client.close(); 
}

访问产品服务 api

让我们创建一个简单的应用程序来从 web 服务器获取产品数据,然后使用 listview 显示产品。

在 android studio 中新建一个 flutter 应用程序 product_rest_app。

将默认启动代码 (main.dart) 替换为我们的 product_nav_app 代码。

将 assets 文件夹从 product_nav_app 复制到 product_rest_app 并在 pubspec.yaml 文件中添加资源。

flutter: 
   assets: 
      - assets/appimages/floppy.png 
      - assets/appimages/iphone.png 
      - assets/appimages/laptop.png 
      - assets/appimages/pendrive.png 
      - assets/appimages/pixel.png 
      - assets/appimages/tablet.png

在 pubspec.yaml 文件中配置 http 包,如下所示 -

dependencies:
http: ^0.12.0 2

在这里,我们将使用最新版本的 http 包。android studio 将发送一个包警报,告知 pubspec.yaml 已更新。

最新版本

单击获取依赖项选项。android studio 将从 internet 获取包并为应用程序正确配置它。

在 main.dart 文件中导入 http 包 -

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;

使用产品信息创建一个新的 json 文件 products.json,如下所示 -

[ 
   { 
      "name": "iphone", 
      "description": "iphone is the stylist phone ever", 
      "price": 1000, 
      "image": "iphone.png" 
   }, 
   { 
      "name": "pixel", 
      "description": "pixel is the most feature phone ever", 
      "price": 800, 
      "image": "pixel.png"
   }, 
   { 
      "name": "laptop", 
      "description": "laptop is most productive development tool", 
      "price": 2000, 
      "image": "laptop.png" 
   }, 
   { 
      "name": "tablet", 
      "description": "tablet is the most useful device ever for meeting", 
      "price": 1500, 
      "image": "tablet.png" 
   }, 
   { 
      "name": "pendrive", 
      "description": "pendrive is useful storage medium", 
      "price": 100, 
      "image": "pendrive.png" 
   }, 
   { 
      "name": "floppy drive", 
      "description": "floppy drive is useful rescue storage medium", 
      "price": 20, 
      "image": "floppy.png" 
   } 
]

创建一个新文件夹 jsonwebserver 并放置 json 文件 products.json。

以 jsonwebserver 作为其根目录运行任何 web 服务器并获取其 web 路径。例如,http://192.168.184.1:8000/products.json 。我们可以使用任何 web 服务器,如 apache、nginx 等,

最简单的方法是安装基于节点的 http-server 应用程序。按照下面给出的步骤安装和运行 http-server 应用程序

  • 安装 nodejs 应用程序
  • 转到 jsonwebserver 文件夹。
cd /path/to/jsonwebserver

使用 npm 安装 http-server 包。

$ npm install -g http-server

现在,运行服务器。

$ http-server . -p 8000
starting up http-server, serving .
available on:
http://192.168.99.1:8000
http://127.0.0.1:8000
hit ctrl-c to stop the server

在 lib 文件夹中创建一个新文件 product.dart 并将 product 类移动到其中。

在 product 类中编写一个工厂构造函数 product.frommap 将映射的数据 map 转换为 product 对象。通常情况下,json 文件会先转换为 dart map 对象,然后再转换为相关对象(product)。

factory product.fromjson(map data) {
   return product(
      data['name'],
      data['description'], 
      data['price'],
      data['image'],
   );
}

product.dart 的完整代码如下 -

class product {
   final string name; 
   final string description;
   final int price;
   final string image; 
   
   product(this.name, this.description, this.price, this.image); 
   factory product.frommap(map json) { 
      return product( 
         json['name'], 
         json['description'], 
         json['price'], 
         json['image'], 
      );
   }
}

在主类中编写两个方法 - parseproductsfetchproducts - 以从 web 服务器获取产品信息并将其加载到 list 对象中。

list parseproducts(string responsebody) { 
   final parsed = json.decode(responsebody).cast>(); 
   return parsed.map((json) =>product.fromjson(json)).tolist(); 
} 
future> fetchproducts() async { 
   final response = await http.get('http://192.168.1.2:8000/products.json'); 
   if (response.statuscode == 200) { 
      return parseproducts(response.body); 
   } else { 
      throw exception('unable to fetch products from the rest api');
   } 
}

请注意以下几点 -

  • future 用于延迟加载产品信息。延迟加载是一个将代码执行推迟到必要时执行的概念。
  • http.get 用于从 internet 获取数据。
  • json.decode 用于将 json 数据解码为 dart map 对象。解码 json 数据后,将使用 product 类的 frommap 将其转换为 list

在 myapp 类中,添加新成员变量,future 类型的产品,并将其包含在构造函数中。

class myapp extends statelesswidget {
final future> products;
myapp({key key, this.products}) : super(key: key);
...

在 myhomepage 类中,添加 future 类型的新成员变量 products 并将其包含在构造函数中。此外,删除 items 变量及其相关方法,getproducts 方法调用。将 products 变量放在构造函数中。它只允许在应用程序首次启动时从 internet 获取产品一次。

class myhomepage extends statelesswidget {
final string title;
final future> products;
myhomepage({key key, this.title, this.products}) : super(key: key);
...

在 myapp 小部件的构建方法中更改ag捕鱼王app官网主页选项(myhomepage)以适应上述更改 -

home: myhomepage(title: 'product navigation demo home page', products: products),

更改主函数以包含 future 参数

void main() => runapp(myapp(fetchproduct()));

创建一个新的小部件 productboxlist 以在ag捕鱼王app官网主页中构建产品列表。

class productboxlist extends statelesswidget { 
   final list items;
   productboxlist({key key, this.items}); 
   
   @override 
   widget build(buildcontext context) {
      return listview.builder(
         itemcount: items.length,
         itembuilder: (context, index) {
            return gesturedetector(
               child: productbox(item: items[index]), 
               ontap: () {
                  navigator.push(
                     context, materialpageroute(
                        builder: (context) =gt; productpage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      ); 
   } 
}

请注意,我们使用导航应用程序中使用的相同概念来列出产品,只是它通过传递 list 类型的产品(对象)设计为单独的小部件。

最后,修改myhomepage小部件的构建方法,以使用 future 选项而不是普通的方法调用来获取产品信息。

widget build(buildcontext context) { 
   return scaffold(
      appbar: appbar(title: text("product navigation")),
      body: center(
         child: futurebuilder>(
            future: products, builder: (context, snapshot) {
               if (snapshot.haserror) print(snapshot.error); 
               return snapshot.hasdata ? productboxlist(items: snapshot.data)
               
               // return the listview widget : 
               center(child: circularprogressindicator()); 
            }, 
         ), 
      )
   ); 
}

这里请注意,我们使用 futurebuilder 小部件来呈现小部件。futurebuilder 将尝试从它的未来属性(future> 类型)中获取数据。如果 future 属性返回数据,它将使用 productboxlist 呈现小部件,否则抛出错误。

main.dart 的完整代码如下 -

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'dart:convert'; 
import 'package:http/http.dart' as http; 
import 'product.dart'; 
void main() => runapp(myapp(products: fetchproducts())); 
list parseproducts(string responsebody) { 
   final parsed = json.decode(responsebody).cast>(); 
   return parsed.map((json) => product.frommap(json)).tolist(); 
} 
future> fetchproducts() async { 
   final response = await http.get('http://192.168.1.2:8000/products.json'); 
   if (response.statuscode == 200) { 
      return parseproducts(response.body); 
   } else { 
      throw exception('unable to fetch products from the rest api'); 
   } 
}
class myapp extends statelesswidget {
   final future> products; 
   myapp({key key, this.products}) : super(key: key); 
   
   // this widget is the root of your application. 
   @override 
   widget build(buildcontext context) {
      return materialapp(
         title: 'flutter demo', 
         theme: themedata( 
            primaryswatch: colors.blue, 
         ), 
         home: myhomepage(title: 'product navigation demo home page', products: products), 
      ); 
   }
}
class myhomepage extends statelesswidget { 
   final string title; 
   final future> products; 
   myhomepage({key key, this.title, this.products}) : super(key: key); 
   
   // final items = product.getproducts();
   @override 
   widget build(buildcontext context) { 
      return scaffold(
         appbar: appbar(title: text("product navigation")), 
         body: center(
            child: futurebuilder>(
               future: products, builder: (context, snapshot) {
                  if (snapshot.haserror) print(snapshot.error); 
                  return snapshot.hasdata ? productboxlist(items: snapshot.data) 
                  
                  // return the listview widget : 
                  center(child: circularprogressindicator()); 
               },
            ),
         )
      );
   }
}
class productboxlist extends statelesswidget {
   final list items; 
   productboxlist({key key, this.items}); 
   
   @override 
   widget build(buildcontext context) {
      return listview.builder(
         itemcount: items.length, 
         itembuilder: (context, index) { 
            return gesturedetector( 
               child: productbox(item: items[index]), 
               ontap: () { 
                  navigator.push(
                     context, materialpageroute( 
                        builder: (context) => productpage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      ); 
   } 
} 
class productpage extends statelesswidget { 
   productpage({key key, this.item}) : super(key: key); 
   final product item; 
   @override 
   widget build(buildcontext context) {
      return scaffold(
         appbar: appbar(title: text(this.item.name),), 
         body: center( 
            child: container(
               padding: edgeinsets.all(0), 
               child: column( 
                  mainaxisalignment: mainaxisalignment.start, 
                  crossaxisalignment: crossaxisalignment.start, 
                  children: [
                     image.asset("assets/appimages/"   this.item.image), 
                     expanded( 
                        child: container( 
                           padding: edgeinsets.all(5), 
                           child: column( 
                              mainaxisalignment: mainaxisalignment.spaceevenly, 
                              children: [ 
                                 text(this.item.name, style: 
                                    textstyle(fontweight: fontweight.bold)), 
                                 text(this.item.description), 
                                 text("price: "   this.item.price.tostring()), 
                                 ratingbox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class ratingbox extends statefulwidget { 
   @override 
   _ratingboxstate createstate() =>_ratingboxstate(); 
} 
class _ratingboxstate extends state { 
   int _rating = 0; 
   void _setratingasone() {
      setstate(() { 
         _rating = 1; 
      }); 
   }
   void _setratingastwo() {
      setstate(() {
         _rating = 2; 
      }); 
   }
   void _setratingasthree() { 
      setstate(() {
         _rating = 3; 
      }); 
   }
   widget build(buildcontext context) {
      double _size = 20; 
      print(_rating); 
      return row(
         mainaxisalignment: mainaxisalignment.end, 
         crossaxisalignment: crossaxisalignment.end, 
         mainaxissize: mainaxissize.max, 
         
         children: [
            container(
               padding: edgeinsets.all(0), 
               child: iconbutton( 
                  icon: (
                     _rating >= 1 
                     ? icon(icons.star, ize: _size,) 
                     : icon(icons.star_border, size: _size,)
                  ), 
                  color: colors.red[500], onpressed: _setratingasone, iconsize: _size, 
               ), 
            ), 
            container(
               padding: edgeinsets.all(0), 
               child: iconbutton(
                  icon: (
                     _rating >= 2 
                     ? icon(icons.star, size: _size,) 
                     : icon(icons.star_border, size: _size, )
                  ), 
                  color: colors.red[500], 
                  onpressed: _setratingastwo, 
                  iconsize: _size, 
               ), 
            ), 
            container(
               padding: edgeinsets.all(0), 
               child: iconbutton(
                  icon: (
                     _rating >= 3 ? 
                     icon(icons.star, size: _size,)
                     : icon(icons.star_border, size: _size,)
                  ), 
                  color: colors.red[500], 
                  onpressed: _setratingasthree, 
                  iconsize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
}
class productbox extends statelesswidget {
   productbox({key key, this.item}) : super(key: key); 
   final product item; 
   
   widget build(buildcontext context) {
      return container(
         padding: edgeinsets.all(2), height: 140, 
         child: card(
            child: row( 
               mainaxisalignment: mainaxisalignment.spaceevenly, 
               children: [
                  image.asset("assets/appimages/"   this.item.image), 
                  expanded( 
                     child: container( 
                        padding: edgeinsets.all(5), 
                        child: column( 
                           mainaxisalignment: mainaxisalignment.spaceevenly, 
                           children: [ 
                              text(this.item.name, style:textstyle(fontweight: fontweight.bold)), 
                              text(this.item.description), 
                              text("price: "   this.item.price.tostring()), 
                              ratingbox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   } 
}

最后运行应用程序以查看结果。它将与我们的导航示例相同,只是数据来自 internet,而不是在编写应用程序时输入的本地静态数据。

查看笔记

扫码一下
查看教程更方便
网站地图