Flutter Bloc Pattern 8.0.0 Call API
Let's Learn how to call API/Webservices using bloc pattern of flutter
What is bloc?
So as per official site of Bloc. The goal of this package is to make it easy to implement the BLoC
Design Pattern (Business Logic Component).
This design pattern helps to separate presentation from business logic. Following the BLoC pattern facilitates testability and reusability. This package abstracts reactive aspects of the pattern allowing developers to focus on writing the business logic.
Bloc
A Bloc
is a more advanced class which relies on events
to trigger state
changes rather than functions. Bloc
also extends BlocBase
which means it has a similar public API as Cubit
. However, rather than calling a function
on a Bloc
and directly emitting a new state
, Blocs
receive events
and convert the incoming events
into outgoing states
.
Lets Start with code.
Create your own Bloc class
class APIBloc extends Bloc<APIEvents, APIState> {
//
final APIRepo apiRepo;
APIBloc({required this.apiRepo}) : super(APIInitState()) {
on<APIEvents>(_addToValue);
}
Future<void> _addToValue(APIEvents event, Emitter<APIState> emit) async {
print("onEvent");
emit(APILoading());
emit.forEach(
Stream.fromFuture(_callAPI(event).catchError((onError) {
return onError;
})), onData: (value) {
if (value is Response)
return APILoaded(response: value as Response);
else {
return value as APIListError;
}
});
}
Future<Object> _callAPI(APIEvents event) async {
try {
if (event is FetchDashBoard) {
return await apiRepo.getDashboardData(event.requestParams);
} else {
throw (APIListError(
error: NoInternetException('No Internet'),
));
}
} on SocketException {
throw (APIListError(
error: NoInternetException('No Internet'),
));
} on HttpException {
throw (APIListError(
error: NoServiceFoundException('No Service Found'),
));
} on FormatException {
throw (APIListError(
error: InvalidFormatException('Invalid Response format'),
));
} catch (e) {
throw (APIListError(
error: UnknownException('Unknown Error'),
));
}
}
}
Now we need 2 Abstract classes for our bloc Events and States
Events of Above bloc:
abstract class APIEvents {}
class DoLogin extends APIEvents {
Object requestParams;
DoLogin({required this.requestParams});
}
class FetchDashBoard extends APIEvents {
Object requestParams;
FetchDashBoard({required this.requestParams});
}Manage States of Bloc:
abstract class APIState extends Equatable {
@override
List<Object> get props => [];
}
class APIInitState extends APIState {}
class APILoading extends APIState {}
class APILoaded extends APIState {
final Response response;
APILoaded({required this.response});
}
class APIListError extends APIState {
final error;
APIListError({this.error});
}You need custom exception classes:
class NoInternetException {
var message;
NoInternetException(this.message);
}
class NoServiceFoundException {
var message;
NoServiceFoundException(this.message);
}
class InvalidFormatException {
var message;
InvalidFormatException(this.message);
}
class UnknownException {
var message;
UnknownException(this.message);
}And Last we have to create our services who makes actuall calls to API.
abstract class APIRepo {
Future<Response> getDashboardData(Object requestParams);
}
class APIServices implements APIRepo {
//
//Pay BusinessURL
static const _payBaseUrl = 'XYZ.net';
static const String _GET_DASHBOARD_DATA = '/dashboard';
static const String _LOGIN ='/user';
@override
Future<Response> getDashboardData(Object requestParams) async {
// TODO: implement getDashboardData
Uri uri = Uri.https(_payBaseUrl, _GET_DASHBOARD_DATA);
print("body " + uri.host);
Response response = await http.post(uri, body: json.encode(requestParams));
return response;
}
}------------------------------------------Now lets make Actual call from our UI screens.
Make your main parent class as BlocProvider
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Preferences.init();
runApp(BlocProvider<APIBloc>(
create: (context) => APIBloc(apiRepo: APIServices()),
child: MyApp(),
));
}now inside your UI dart file in initstate call below API.
so it call API when loading.
you can call below line anywhere like button click, link click etc
@override
void initState() {
super.initState();
_loadData();
// readJson();
}
_loadData() async {
context.read<APIBloc>().add(FetchDashBoard(requestParams: inputParams));
}@override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBarWidget.getAppBar(AppLocalizations.of(context)!.login),
body: Container(
child: _body(),
),
);
}_body() {
return BlocListener<APIBloc, APIState>(
child: loadDeshboardUIAfterCall(),
listener: (context, state) {
if (state is APIListError) {
final error = state.error;
String message = '${error.message}';
WidgetsBinding.instance!.addPostFrameCallback((_) {
BasicWidget.showSnackBar(context, message);
Navigator.of(_keyLoader.currentContext!, rootNavigator: true)
.pop();
});
Navigator.of(_keyLoader.currentContext!, rootNavigator: true)
.pop();
}
if (state is APILoaded) {
print("Loaded");
WidgetsBinding.instance!.addPostFrameCallback((_) {
print(state.response.body);
Navigator.of(_keyLoader.currentContext!, rootNavigator: true)
.pop();
setState(() {
dashboard =
Dashboard.fromJson(json.decode(state.response.body));
});
});
}
if (state is APILoading) {
print("Loading");
WidgetsBinding.instance!.addPostFrameCallback((_) {
ProgressDialogs.showLoadingDialog(context, _keyLoader);
});
}
});
}Here you go. now just load screen you will get your response and then render it in UI.
Comments
Post a Comment