Enfin, nous sommes arrivés à l'un des sujets les plus importants, sans lequel il ne sert à rien d'aller plus loin.
Le plan est assez simple : nous devons nous familiariser avec l'architecture client-serveur et implémenter la liste des postes.
En fin de compte, nous organiserons correctement nos fichiers de page et déplacerons l'élément de liste dans un fichier séparé.
Volons!
Notre plan
Partie 1 - introduction au développement, première annexe, notion d'état ;
Partie 2 - fichier pubspec.yaml et utilisation de flutter sur la ligne de commande ;
Partie 3 - BottomNavigationBar et Navigator ;
Partie 4 - MVC. Nous utiliserons ce modèle particulier comme l'un des plus simples ;
Partie 5 (article actuel) - package http. Création de la classe Repository, premières demandes, listing des posts ;
Partie 6 - travailler avec des formulaires, des zones de texte et créer un article.
Partie 7 - travailler avec des images, afficher des images sous forme de grille, recevoir des images du réseau, ajouter les vôtres à l'application;
Partie 8 - créer votre propre thème, ajouter des polices et des animations personnalisées ;
Partie 9 - un peu sur les tests;
Client et serveur
Le modèle Client/Serveur est au cœur de tout Internet et est le plus répandu.
Quelle est son essence ?
Tout d'abord, voyons ce que sont un client et un serveur :
Client - Une machine utilisateur qui envoie des demandes au serveur et reçoit des réponses. Il peut s'agir d'un smartphone, d'un ordinateur ou d'un MacBook.
Le serveur est un ordinateur spécial qui contient les données requises par l'utilisateur.
L'ensemble du modèle se résume à un principe primitif : le client envoie une requête, le serveur l'accepte, la traite et transmet la réponse au client.
Pour organiser l'interaction entre le serveur et le client, des protocoles spéciaux sont utilisés. À l'heure actuelle, l'un des protocoles les plus courants sur Internet est http / https (s signifie sécurisé).
http / https vous permet de transférer presque tous les formats de données connus : images, vidéo, texte.
Nous travaillerons avec le format JSON .
JSON est un format de données simple et compréhensible, et surtout léger, car seul le texte est transmis.
Exemple JSON :
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
...
]
Voici un tableau des messages que nous recevrons du serveur.
: , .
JSON :
{
"total_items" : 1
"result" : [
{
"id" : 1,
"name" : "Twillight Sparkle",
"pony_type" : "alicorn",
"friends" : [
"Starlight Glimmer", "Applejack", "Rarity", "Spike"
]
}
]
}
.
.. http / https HTTP .
HTTP :
URL - , , . URL : https://jsonplaceholder.typicode.com/posts. ( URL' )
, . GET , POST , DELETE - , PUT - .
POST, PUT DELETE . GET URL'. : https://jsonplaceholder.typicode.com/posts/1 ( id = 1)
http
.
, pubspec.yaml
:
# dependencies: flutter: sdk: flutter # pub- # # flutter_staggered_grid_view: ^0.4.0 # MVC mvc_pattern: ^7.0.0 # http # http: ^0.13.3
.
post.dart
models
:
//
class Post {
// private
//
final int _userId;
final int _id;
final String _title;
final String _body;
// getters
//
int get userId => _userId;
int get id => _id;
String get title => _title;
String get body => _body;
// Dart
// Post.fromJson(json) -
// JSON
// , dynamic
// : String, int, double ..
Post.fromJson(Map<String, dynamic> json) :
this._userId = json["userId"],
this._id = json["id"],
this._title = json["title"],
this._body = json["body"];
}
// PostList
class PostList {
final List<Post> posts = [];
PostList.fromJson(List<dynamic> jsonItems) {
for (var jsonItem in jsonItems) {
posts.add(Post.fromJson(jsonItem));
}
}
}
//
//
//
abstract class PostResult {}
//
class PostResultSuccess extends PostResult {
final PostList postList;
PostResultSuccess(this.postList);
}
//
class PostResultFailure extends PostResult {
final String error;
PostResultFailure(this.error);
}
//
class PostResultLoading extends PostResult {
PostResultLoading();
}
.
JSON :
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
, userId
id
, title
body
, Post.fromJson(json)
.
Repository
.
data
repository.dart
:
import 'dart:convert';
// http
import 'package:http/http.dart' as http;
import 'package:json_placeholder_app/models/post.dart';
//
// SERVER
const String SERVER = "https://jsonplaceholder.typicode.com";
class Repository {
//
// Future ,
// fetchPhotos
// UI
Future<PostList> fetchPosts() async {
// URL,
//
final url = Uri.parse("$SERVER/posts");
// GET
final response = await http.get(url);
//
if (response.statusCode == 200) {
//
// json.decode
return PostList.fromJson(json.decode(response.body));
} else {
//
throw Exception("failed request");
}
}
}
: , ?
.. , .
. URL .
PostController
:
import '../data/repository.dart';
import '../models/post.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostController extends ControllerMVC {
//
final Repository repo = new Repository();
//
PostController();
// -
PostResult currentState = PostResultLoading();
void init() async {
try {
//
final postList = await repo.fetchPosts();
//
setState(() => currentState = PostResultSuccess(postList));
} catch (error) {
//
setState(() => currentState = PostResultFailure(" "));
}
}
}
: :
import 'package:flutter/material.dart';
import '../controllers/post_controller.dart';
import '../models/post.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostListPage extends StatefulWidget {
@override
_PostListPageState createState() => _PostListPageState();
}
// StateMVC
class _PostListPageState extends StateMVC {
//
PostController _controller;
// StateMVC
//
_PostListPageState() : super(PostController()) {
_controller = controller as PostController;
}
//
//
@override
void initState() {
super.initState();
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Post List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PostResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PostResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.red)
),
);
} else {
//
final posts = (state as PostResultSuccess).postList.posts;
return Padding(
padding: EdgeInsets.all(10),
// ListView.builder
//
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
return _buildPostItem(posts[index]);
},
),
);
}
}
//
Widget _buildPostItem(Post post) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(color: Colors.grey.withOpacity(0.5), width: 0.3)
),
margin: EdgeInsets.only(bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)),
color: Theme.of(context).primaryColor,
),
padding: EdgeInsets.all(10),
child: Text(
post.title,
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white),),
),
Container(
child: Text(
post.body,
style: Theme.of(context).textTheme.bodyText2,
),
padding: EdgeInsets.all(10),
),
],
)
);
}
}
.
, )
:
! :
!
.
post_list_page.dart
110 , . 10 20 !
, .
.
Widget _buildItem(post)
.
:
post post_list_item.dart:
import 'package:flutter/material.dart';
import '../../models/post.dart';
//
class PostListItem extends StatelessWidget {
final Post post;
//
PostListItem(this.post);
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(color: Colors.grey.withOpacity(0.5), width: 0.3)
),
margin: EdgeInsets.only(bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)),
color: Theme.of(context).primaryColor,
),
padding: EdgeInsets.all(10),
child: Text(
post.title,
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white),),
),
Container(
child: Text(
post.body,
style: Theme.of(context).textTheme.bodyText2,
),
padding: EdgeInsets.all(10),
),
],
)
);
}
}
post_list_page.dart
:
import 'package:flutter/material.dart';
import '../../controllers/post_controller.dart';
import '../../models/post.dart';
import 'post_list_item.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostListPage extends StatefulWidget {
@override
_PostListPageState createState() => _PostListPageState();
}
// StateMVC
class _PostListPageState extends StateMVC {
//
PostController _controller;
// StateMVC
//
_PostListPageState() : super(PostController()) {
_controller = controller as PostController;
}
//
//
@override
void initState() {
super.initState();
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Post List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PostResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PostResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.red)
),
);
} else {
//
final posts = (state as PostResultSuccess).postList.posts;
return Padding(
padding: EdgeInsets.all(10),
// ListView.builder
//
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
//
//
return PostListItem(posts[index]);
},
),
);
}
}
}
.
J'ai essayé de raconter brièvement et de montrer par un exemple illustratif comment travailler avec le réseau.
J'espère que mon article vous a été utile)
Bon code à tous !