Flutter网络数据请求与BLoC模式结合插件bloc_rest_api的使用
Flutter网络数据请求与BLoC模式结合插件bloc_rest_api的使用
bloc_rest_api简介
bloc_rest_api
是一个用于轻松集成和管理 REST API 的 Flutter 包。只需创建一个模型类,其余的工作都将由该包处理。
特性:
- 支持所有平台(Android、iOS、Web、Linux、Windows、Mac)。
- 集成 BLoC 模式,便于状态管理。
- 提供多种方法来处理网络请求,包括 GET、POST 等。
使用步骤
1. 添加依赖
在 pubspec.yaml
文件中添加 bloc_rest_api
依赖:
dependencies:
bloc_rest_api: <最新版本>
然后执行以下命令安装依赖:
# Dart
pub get
# Flutter
flutter pub get
2. 创建数据模型
首先,我们需要为要从互联网获取的数据创建一个模型类。可以使用工具如 QuickType 来快速生成模型类。
示例:创建一个 PostModel
类。
import 'package:equatable/equatable.dart';
class PostModel extends Equatable {
PostModel({
this.userId,
this.id,
this.title,
this.body,
});
final int userId;
final int id;
final String title;
final String body;
factory PostModel.fromJson(Map<String, dynamic> json) => PostModel(
userId: json['userId'] ?? null,
id: json['id'] ?? null,
title: json['title'] ?? null,
body: json['body'] ?? null,
);
Map<String, dynamic> toJson() => {
'userId': userId,
'id': id,
'title': title,
'body': body,
};
[@override](/user/override)
List<Object> get props => [userId, id];
}
3. 配置 RequestCubit
接下来,我们需要配置 RequestCubit
来处理网络请求。通过 BlocProvider
注册 RequestCubit
,并传递 fromMap
方法以将 JSON 转换为模型对象。
MultiBlocProvider(
providers: [
// 单个模型的请求
BlocProvider(
create: (context) => RequestCubit<PostModel>(
fromMap: (json) => PostModel.fromJson(json),
),
),
// 列表模型的请求
BlocProvider(
create: (context) => RequestCubit<List<PostModel>>(
fromMap: (json) =>
List<PostModel>.from(json.map((x) => PostModel.fromJson(x))),
),
),
],
child: AppView(),
);
4. 发起网络请求
使用 context.read()
调用 getRequest
或 postRequest
方法发起网络请求。
context.read<RequestCubit<PostModel>>().getRequest(
baseUrl: 'https://jsonplaceholder.typicode.com/',
handle: 'posts/1',
);
如果需要启用日志功能,可以通过设置 enableLogs
参数为 true
:
context.read<RequestCubit<PostModel>>().getRequest(
baseUrl: 'https://jsonplaceholder.typicode.com/',
handle: 'posts/1',
enableLogs: true,
);
如果需要从本地 JSON 字符串中读取数据:
context.read<RequestCubit<PostModel>>().localRequest(
'json string here',
);
5. 处理复杂数据
对于更复杂的场景,可以传递一个返回 Future<T>
的函数作为参数。
Future<PostModel> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
if (response.statusCode == 200) {
return PostModel.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load album');
}
}
// 调用
context.read<RequestCubit<PostModel>>().request(fetchAlbum);
6. 反应状态变化
使用 BlocBuilder
、BlocListener
或 BlocConsumer
监听状态变化,并根据状态更新 UI。
BlocBuilder<RequestCubit<PostModel>, RequestState<PostModel>>(
builder: (context, state) {
switch (state.status) {
case RequestStatus.empty:
return Center(child: Text('Press the button to get some data'));
case RequestStatus.loading:
return Center(child: CircularProgressIndicator());
case RequestStatus.success:
return Center(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Text(state.model.toString()),
),
);
case RequestStatus.failure:
return Center(child: Text(state.errorMessage));
default:
return Container();
}
},
);
全局配置
可以通过 ApiConfig
设置全局配置,例如基础 URL、请求头和超时时间。
ApiConfig.baseUrl = 'https://jsonplaceholder.typicode.com/';
ApiConfig.header = {'Content-Type': 'application/json'};
ApiConfig.responseTimeOut = Duration(seconds: 10);
持久化数据
如果需要持久化 API 数据,可以使用 HydratedRequestCubit
替换 RequestCubit
,并提供 fromMap
和 toMap
方法。
BlocProvider(
create: (context) => HydratedRequestCubit<PostModel>(
fromMap: (json) => PostModel.fromJson(json),
toMap: (model) => model.toJson(),
),
)
同时初始化存储:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
HydratedBloc.storage = await HydratedStorage.build();
runApp(App());
}
完整示例代码
以下是一个完整的示例代码,展示了如何使用 bloc_rest_api
进行网络请求和状态管理。
import 'dart:convert';
import 'package:bloc_rest_api/bloc_rest_api.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:http/http.dart' as http;
import 'models/models.dart';
void main() {
// 设置全局配置
ApiConfig.baseUrl = "https://jsonplaceholder.typicode.com/";
ApiConfig.header = {"Content-Type": "application/json"};
runApp(App());
}
class App extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
// 单个模型的请求
BlocProvider(
create: (context) => RequestCubit<PostModel>(
fromMap: (json) => PostModel.fromJson(json),
),
),
// 列表模型的请求
BlocProvider(
create: (context) => RequestCubit<List<PostModel>>(
fromMap: (json) =>
List<PostModel>.from(json.map((x) => PostModel.fromJson(x))),
),
),
],
child: AppView(),
);
}
}
class AppView extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(title: 'Example App'),
);
}
}
class HomePage extends StatelessWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<RequestCubit<PostModel>>().getRequest(
handle: 'posts/1',
);
},
child: Icon(Icons.add),
),
body: BlocConsumer<RequestCubit<PostModel>, RequestState<PostModel>>(
listener: (context, state) {
if (state.status == RequestStatus.failure) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(state.errorMessage)),
);
}
},
builder: (context, state) {
switch (state.status) {
case RequestStatus.empty:
return Center(child: Text("Press the button to get some data"));
case RequestStatus.loading:
return Center(child: CircularProgressIndicator());
case RequestStatus.success:
return Center(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Text(state.model.toString()),
),
);
case RequestStatus.failure:
return Center(child: Text(state.errorMessage));
default:
return Container();
}
},
),
);
}
}
Future<PostModel> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
if (response.statusCode == 200) {
return PostModel.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load album');
}
}
更多关于Flutter网络数据请求与BLoC模式结合插件bloc_rest_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网络数据请求与BLoC模式结合插件bloc_rest_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,BLoC(Business Logic Component)模式是一种非常流行的状态管理方式,它可以帮助你将业务逻辑与UI层分离,使代码更加清晰和可维护。bloc_rest_api
是一个结合了BLoC模式和网络数据请求的插件,它可以帮助你更轻松地处理REST API请求。
1. 安装依赖
首先,你需要在 pubspec.yaml
文件中添加 bloc
和 bloc_rest_api
依赖:
dependencies:
flutter:
sdk: flutter
bloc: ^8.0.0
flutter_bloc: ^8.0.0
bloc_rest_api: ^0.0.1
然后运行 flutter pub get
来安装依赖。
2. 创建BLoC
接下来,你可以创建一个BLoC来处理网络请求。假设你要从API获取用户数据,你可以创建一个 UserBloc
。
import 'package:bloc/bloc.dart';
import 'package:bloc_rest_api/bloc_rest_api.dart';
import 'package:equatable/equatable.dart';
part 'user_event.dart';
part 'user_state.dart';
class UserBloc extends Bloc<UserEvent, UserState> {
final ApiClient apiClient;
UserBloc({required this.apiClient}) : super(UserInitial());
[@override](/user/override)
Stream<UserState> mapEventToState(UserEvent event) async* {
if (event is FetchUser) {
yield UserLoading();
try {
final user = await apiClient.getUser(event.userId);
yield UserLoaded(user);
} catch (e) {
yield UserError(e.toString());
}
}
}
}
3. 定义事件和状态
你需要定义 UserEvent
和 UserState
来处理不同的事件和状态。
user_event.dart
:
part of 'user_bloc.dart';
abstract class UserEvent extends Equatable {
const UserEvent();
[@override](/user/override)
List<Object> get props => [];
}
class FetchUser extends UserEvent {
final String userId;
const FetchUser(this.userId);
[@override](/user/override)
List<Object> get props => [userId];
}
user_state.dart
:
part of 'user_bloc.dart';
abstract class UserState extends Equatable {
const UserState();
[@override](/user/override)
List<Object> get props => [];
}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
final User user;
const UserLoaded(this.user);
[@override](/user/override)
List<Object> get props => [user];
}
class UserError extends UserState {
final String message;
const UserError(this.message);
[@override](/user/override)
List<Object> get props => [message];
}
4. 创建ApiClient
ApiClient
是一个用于处理网络请求的类。你可以使用 bloc_rest_api
提供的 RestApiClient
来简化网络请求。
import 'package:bloc_rest_api/bloc_rest_api.dart';
class ApiClient {
final RestApiClient restApiClient;
ApiClient({required this.restApiClient});
Future<User> getUser(String userId) async {
final response = await restApiClient.get('/users/$userId');
return User.fromJson(response);
}
}
5. 在UI中使用BLoC
最后,你可以在UI中使用 UserBloc
来获取和显示用户数据。
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class UserScreen extends StatelessWidget {
final String userId;
const UserScreen({Key? key, required this.userId}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => UserBloc(apiClient: ApiClient(restApiClient: RestApiClient(baseUrl: 'https://api.example.com')))..add(FetchUser(userId)),
child: Scaffold(
appBar: AppBar(
title: Text('User Details'),
),
body: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is UserLoaded) {
return Center(child: Text('User: ${state.user.name}'));
} else if (state is UserError) {
return Center(child: Text('Error: ${state.message}'));
} else {
return Center(child: Text('Initial State'));
}
},
),
),
);
}
}