I mentioned in my previous post that I am learning Flutter to implement & publish my App KidzTokenz on Apple App Store & so far, I am enjoying the experience, and I signed up for the #30DaysOfFlutter starting on Feb 1
In this post, we are going to follow the BLoC pattern to integrate with the users API on {JSON} Placeholder and build an app to do the following:
- Use the http package for making the HTTP requests.
- Wrap the API call with the BLoC pattern.
- Use Streams to display the users' list & the users' count.
Let's start by creating an App using the command below using Terminal.
flutter create http_for_flutter
Add the http package to the pubspec.yaml file
dependencies:
flutter:
sdk: flutter
http: ^0.12.2
Create the user.dart file below in the (lib\models) folder, we will create the User from the API's json response.
class User {
final String name;
final String email;
final String symbol;
final String phone;
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
email = json['email'],
symbol = json['username'].toString().substring(0, 1),
phone = json['phone'];
}
Create the users_service.dart file below in the (lib\services) folder. We will convert the API's response to a list of users.
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
import 'package:http_for_flutter/models/user.dart';
class UserService {
static String _url = 'https://jsonplaceholder.typicode.com/users';
static Future browse() async {
List collection;
List<User> _contacts;
var response = await http.get(_url);
if (response.statusCode == 200) {
collection = convert.jsonDecode(response.body);
_contacts = collection.map((json) => User.fromJson(json)).toList();
} else {
print('Request failed with status: ${response.statusCode}.');
}
return _contacts;
}
}
Create the user_bloc.dart file below in the (lib\bloc) folder. UserBLoC will be the middleman between the source of data (UserService) and the widget.
Note how we are listening to the usersList stream to update the userCounter stream
import 'dart:async';
import 'package:http_for_flutter/models/user.dart';
import 'package:http_for_flutter/services/users_service.dart';
class UserBLoC {
Stream<List<User>> get usersList async* {
yield await UserService.browse();
}
final StreamController<int> _userCounter = StreamController<int>();
Stream<int> get userCounter => _userCounter.stream;
UserBLoC() {
usersList.listen((list) => _userCounter.add(list.length));
}
}
We need to update the main.dart to use a StreamBuilder in the AppBar to display the number of users using the (userBLoC.userCounter) stream, and we will use another one in the body to display the list of users using (userBLoC.usersList) stream.
import 'package:flutter/material.dart';
import 'package:http_for_flutter/bloc/user_bloc.dart';
import 'package:http_for_flutter/models/user.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Users List',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Users List Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
UserBLoC userBLoC = new UserBLoC();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Users'),
actions: [
Chip(
label: StreamBuilder<int>(
stream: userBLoC.userCounter,
builder: (context, snapshot) {
return Text(
(snapshot.data ?? 0).toString(),
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
);
}),
backgroundColor: Colors.red,
),
Padding(
padding: EdgeInsets.only(right: 16),
)
],
),
body: StreamBuilder(
stream: userBLoC.usersList,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError)
return Text('There was an error : ${snapshot.error}');
List<User> users = snapshot.data;
return ListView.separated(
itemCount: users?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
User _user = users[index];
return ListTile(
title: Text(_user.name),
subtitle: Text(_user.email),
leading: CircleAvatar(
child: Text(_user.symbol),
),
);
},
separatorBuilder: (context, index) => Divider(),
);
}
}),
);
}
}
Run the App and you will get the screen below
Check the code here
Follow me on Twitter for more tips about #coding, #learning, #technology...etc.
Check my Apps on Google Play
Cover image Mitchell Kmetz on Unsplash
Top comments (3)
I think you must be update your code into null-safety
your tutorial was easy to implement
good job
Thanks
this code is only one Time Fetch the data,
but need is realtime changes to update live data....