Flutter – Truy cập API REST


Flutter cung cấp gói http để tiêu thụ tài nguyên HTTP. http là một thư viện dựa trên Tương lai và sử dụng các tính năng await và async. Nó cung cấp nhiều phương pháp cấp cao và đơn giản hóa việc phát triển các ứng dụng di động dựa trên REST.

Các khái niệm cơ bản

Gói http cung cấp một lớp cấp cao và http để thực hiện các yêu cầu web.

  • Lớp http cung cấp chức năng để thực hiện tất cả các loại yêu cầu HTTP.

  • Phương thức http chấp nhận một url và thông tin bổ sung thông qua Bản đồ phi tiêu (dữ liệu đăng, tiêu đề bổ sung, v.v.). Nó yêu cầu máy chủ và thu thập phản hồi lại ở dạng không đồng bộ / chờ đợi. Ví dụ: mã dưới đây đọc dữ liệu từ url được chỉ định và in nó trong bảng điều khiển.

print(await http.read('

Một số phương pháp cốt lõi như sau:

  • đọc – Yêu cầu url được chỉ định thông qua phương thức GET và trả lại phản hồi dưới dạng Future

  • lấy – Yêu cầu url được chỉ định thông qua phương thức GET và trả về phản hồi dưới dạng Future . Phản hồi là một lớp nắm giữ thông tin phản hồi.

  • bưu kiện – Yêu cầu url được chỉ định thông qua phương thức POST bằng cách đăng dữ liệu được cung cấp và trả lại phản hồi dưới dạng Future

  • đặt – Yêu cầu url được chỉ định thông qua phương thức PUT và trả lại phản hồi dưới dạng Tương lai

  • cái đầu – Yêu cầu url được chỉ định thông qua phương thức HEAD và trả lại phản hồi dưới dạng Tương lai

  • xóa bỏ – Yêu cầu url được chỉ định thông qua phương thức DELETE và trả lại phản hồi dưới dạng Tương lai

http cũng cung cấp một lớp máy khách HTTP tiêu chuẩn hơn, máy khách. máy khách hỗ trợ kết nối liên tục. Nó sẽ hữu ích khi có nhiều yêu cầu được thực hiện đến một máy chủ cụ thể. Nó cần được đóng đúng cách bằng cách sử dụng phương pháp đóng. Nếu không, nó tương tự như lớp http. Mã mẫu như sau:

var client = new http.Client(); 
try { 
   print(await client.get(' 
} 
finally { 
   client.close(); 
}

Truy cập API dịch vụ sản phẩm

Hãy để chúng tôi tạo một ứng dụng đơn giản để lấy dữ liệu sản phẩm từ máy chủ web và sau đó hiển thị các sản phẩm bằng cách sử dụng ListView.

  • Tạo một cái mới Chớp cánh ứng dụng trong Android studio, product_rest_app.

  • Thay thế mã khởi động mặc định (main.dart) bằng product_nav_app mã số.

  • Sao chép thư mục nội dung từ product_nav_app đến product_rest_app và thêm nội dung bên trong tệp 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
dependencies: 
   http: ^0.12.0+2

Phiên bản mới nhất

  • Nhấp vào Nhận tùy chọn phụ thuộc. Android studio sẽ lấy gói từ Internet và định cấu hình đúng cách cho ứng dụng.

  • Nhập gói http trong tệp main.dart –

import 'dart:async'; 
import 'dart:convert'; 
import 'package:http/http.dart' as http;
[ 
   { 
      "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" 
   } 
]
  • Tạo một thư mục mới, JSONWebServer và đặt tệp JSON, products.json.

  • Chạy bất kỳ máy chủ web nào với JSONWebServer làm thư mục gốc và lấy đường dẫn web của nó. Ví dụ: Chúng tôi có thể sử dụng bất kỳ máy chủ web nào như apache, nginx, v.v.,

  • Cách dễ nhất là cài đặt ứng dụng máy chủ http-dựa trên nút. Làm theo các bước dưới đây để cài đặt và chạy ứng dụng máy chủ http-

    • Cài đặt ứng dụng Nodejs (nodejs.org)

    • Chuyển đến thư mục JSONWebServer.

cd /path/to/JSONWebServer
npm install -g http-server
http-server . -p 8000 

Starting up http-server, serving . 
Available on: 
   
    
   Hit CTRL-C to stop the server
  • Tạo một tệp mới, Product.dart trong thư mục lib và di chuyển lớp Sản phẩm vào đó.

  • Viết một hàm tạo nhà máy trong lớp Sản phẩm, Product.fromMap để chuyển đổi Bản đồ dữ liệu được ánh xạ thành đối tượng Sản phẩm. Thông thường, tệp JSON sẽ được chuyển đổi thành đối tượng Dart Map và sau đó, được chuyển đổi thành đối tượng có liên quan (Sản phẩm).

factory Product.fromJson(Map<String, dynamic> data) {
   return Product(
      data['name'],
      data['description'], 
      data['price'],
      data['image'],
   );
}
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<String, dynamic> json) { 
      return Product( 
         json['name'], 
         json['description'], 
         json['price'], 
         json['image'], 
      );
   }
}
List<Product> parseProducts(String responseBody) { 
   final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); 
   return parsed.map<Product>((json) =>Product.fromJson(json)).toList(); 
} 
Future<List<Product>> fetchProducts() async { 
   final response = await http.get(' 
   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<List<Product>> products; 
   MyApp({Key key, this.products}) : super(key: key); 
   ...
  • Trong lớp MyHomePage, thêm các sản phẩm biến thành viên mới kiểu Future và đưa nó vào hàm khởi tạo. Ngoài ra, hãy xóa biến items và phương thức liên quan của nó, gọi phương thức getProducts. Đặt biến sản phẩm trong hàm khởi tạo. Nó sẽ cho phép tìm nạp các sản phẩm từ Internet chỉ một lần khi ứng dụng được khởi động lần đầu tiên.

class MyHomePage extends StatelessWidget { 
   final String title; 
   final Future<ListList<Product>> products; 
   MyHomePage({Key key, this.title, this.products}) : super(key: key); 
   ...
home: MyHomePage(title: 'Product Navigation demo home page', products: products),
void main() => runApp(MyApp(fetchProduct()));
class ProductBoxList extends StatelessWidget { 
   final List<Product> 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]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      ); 
   } 
}

Lưu ý rằng chúng tôi đã sử dụng cùng một khái niệm được sử dụng trong ứng dụng Điều hướng để liệt kê sản phẩm ngoại trừ nó được thiết kế như một widget riêng biệt bằng cách chuyển các sản phẩm (đối tượng) của loại Danh sách .

Widget build(BuildContext context) { 
   return Scaffold(
      appBar: AppBar(title: Text("Product Navigation")),
      body: Center(
         child: FutureBuilder<List<Product>>(
            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()); 
            }, 
         ), 
      )
   ); 
}
  • Ở đây lưu ý rằng chúng tôi đã sử dụng tiện ích FutureBuilder để hiển thị tiện ích. FutureBuilder sẽ cố gắng tìm nạp dữ liệu từ thuộc tính tương lai của nó (thuộc loại Future >). Nếu thuộc tính trong tương lai trả về dữ liệu, nó sẽ hiển thị tiện ích con bằng cách sử dụng ProductBoxList, nếu không sẽ tạo ra lỗi.

  • Mã hoàn chỉnh của main.dart như sau:

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<Product> parseProducts(String responseBody) { 
   final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); 
   return parsed.map<Product>((json) => Product.fromMap(json)).toList(); 
} 
Future<List<Product>> fetchProducts() async { 
   final response = await http.get(' 
   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<List<Product>> 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<List<Product>> 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<List<Product>>(
               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<Product> 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: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 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<RatingBox> { 
   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: <Widget>[
            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: <Widget>[
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style:TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   } 
}

Cuối cùng là chạy ứng dụng để xem kết quả. Nó sẽ giống như của chúng tôi dẫn đường ví dụ ngoại trừ dữ liệu từ Internet thay vì dữ liệu cục bộ, tĩnh được nhập trong khi mã hóa ứng dụng.