Yêu cầu HTTP với Flutter
Thật khó để thực hiện bất kỳ loại phát triển nào mà không phải thực hiện một số hình thức yêu cầu HTTP, do đó, ta sẽ xem xét cách sử dụng plugin http
trong Flutter.
Tạo một dự án Flutter mới
Để theo dõi quá trình cài đặt , ta sẽ tạo một ứng dụng Flutter mẫu. Giả sử bạn đã cài đặt Flutter và Dart SDK, hãy chạy phần sau trong terminal của bạn:
# New Flutter application $ flutter create flutter_http # Open this up inside of VS Code $ cd flutter_http && code .
Thêm plugin HTTP
Đi tới pubspec.yaml
của bạn và thêm plugin sau:
dependencies: flutter: sdk: flutter http: ^0.12.0+2
Đây là một plugin Flutter chính thức được xuất bản bởi dart.dev và nó có 100 điểm sức khỏe , do đó, ta có thể tin tưởng vào độ tin cậy của plugin này.
Yêu cầu HTTP
Nhiệm vụ đầu tiên của ta sẽ là tạo một lớp mà ta có thể sử dụng để tương tác với API của bạn . Ta sẽ tạo một lớp mới có tên HttpService
tại lib/http_service.dart
và thêm một hàm getPosts
:
class HttpService { final String postsURL = "https://jsonplaceholder.typicode.com/posts"; Future<List<Post>> getPosts() async { Response res = await get(postsURL); if (res.statusCode == 200) { List<dynamic> body = jsonDecode(res.body); List<Post> posts = body .map( (dynamic item) => Post.fromJson(item), ) .toList(); return posts; } else { throw "Can't get posts."; } } }
Như đã thấy từ hàm getPosts
, trước tiên ta đang gọi get
từ gói http
trên postsURL
.
Tiếp theo, nếu yêu cầu đó thành công, ta sẽ phân tích cú pháp phản hồi và trả về một List<Post>
bằng Post.fromJson
. Hãy tiếp tục và tạo lớp Post
tại lib/posts_model.dart
:
import 'package:flutter/foundation.dart'; class Post { final int userId; final int id; final String title; final String body; Post({ @required this.userId, @required this.id, @required this.title, @required this.body, }); factory Post.fromJson(Map<String, dynamic> json) { return Post( userId: json['userId'] as int, id: json['id'] as int, title: json['title'] as String, body: json['body'] as String, ); } }
Để tuần tự hóa phản hồi, ta sẽ trả lại một Post
mới với phương thức fromJson
dựa trên Map
JSON. Trong một ứng dụng production , tôi khuyên bạn nên sử dụng thứ gì đó như json_serializable để xử lý việc tuần tự hóa tự động.
Hiển thị bài đăng
Với ý nghĩ này, hãy tạo một trang mới có tên là PostsPage
tại lib/posts.dart
:
import 'package:flut_http/http_service.dart'; import 'package:flut_http/post_detail.dart'; import 'package:flut_http/post_model.dart'; import 'package:flutter/material.dart'; class PostsPage extends StatelessWidget { final HttpService httpService = HttpService(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Posts"), ), body: FutureBuilder( future: httpService.getPosts(), builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) { if (snapshot.hasData) { List<Post> posts = snapshot.data; return ListView( children: posts .map( (Post post) => ListTile( title: Text(post.title), subtitle: Text("${post.userId}"), onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => PostDetail( post: post, ), ), ), ), ) .toList(), ); } else { return Center(child: CircularProgressIndicator()); } }, ), ); } }
Ta đang sử dụng một FutureBuilder
widget để tương tác với getPosts()
chức năng. Điều này cho phép ta xác định khi nào List<Post>
đã sẵn sàng và hành động theo đó.
Nếu snapshot.hasData
là false, thì ta đang hiển thị CircularProgressIndicator
, nếu không , ta đang hiển thị ListTile
với nhiều thông tin bài đăng khác nhau.
Hãy đảm bảo ta cập nhật main.dart
với trang home
của PostsPage
:
import 'package:flut_http/posts.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'HTTP', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.deepPurple, ), home: PostsPage(), ); } }
Đăng chi tiết
Nếu user nhấn vào bài đăng, ta đang tìm cách chuyển user đến trang PostDetail
. Hãy xây dựng điều đó:
import 'package:flut_http/post_model.dart'; import 'package:flutter/material.dart'; class PostDetail extends StatelessWidget { final Post post; PostDetail({@required this.post}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(post.title), ), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( children: <Widget>[ Card( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ ListTile( title: Text("Title"), subtitle: Text(post.title), ), ListTile( title: Text("ID"), subtitle: Text("${post.id}"), ), ListTile( title: Text("Body"), subtitle: Text(post.body), ), ListTile( title: Text("User ID"), subtitle: Text("${post.userId}"), ), ], ), ), ], ), ), )); } }
Mặc dù trang này không có bất kỳ dữ liệu HTTP nào, nhưng tôi đã chọn thêm dữ liệu này để hiển thị dữ liệu Bài đăng hoàn chỉnh.
XÓA BỎ
Một ví dụ khác về yêu cầu HTTP như vậy là sử dụng phương thức delete
. Ví dụ, bên trong HttpService
ta , ta có thể tạo một phương thức deletePost(int id)
:
Future<void> deletePost(int id) async { Response res = await delete("$postsURL/$id"); if (res.statusCode == 200) { print("DELETED"); } else { throw "Can't delete post."; } }
Ta có thể thêm một IconButton
vào mảng actions
trong AppBar
để khi nào AppBar
vào AppBar
này, một Post
sẽ bị xóa:
final HttpService httpService = HttpService(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(post.title), actions: <Widget>[ IconButton( icon: Icon(Icons.delete), onPressed: () async { await httpService.deletePost(post.id); Navigator.of(context).pop(); }, ) ], ), // ) }
Kết thúc
Trong bài viết này, ta đã xem xét cách tương tác với gói Flutter http
. Điều này cho phép ta có được danh sách các bài đăng, cũng như xóa từng bài đăng.
Các thao tác tương tự như post
, put
, patch
, v.v. cũng có sẵn. Kiểm tra tài liệu để biết thêm thông tin về điều này.
Các tin liên quan