使用 Bloc 模式显示从 REST API 获取的数据列表。 现在我想在单击按钮时更新列表视图上的列表。 当我单击按钮时,它会获取数据但不会更新列表视图 这是完整的代码。
main.dart
import 'package:bloc_demo/homepage.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
HomePage.dart
class HomePage extends StatelessWidget {
String pageNo = "1";
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<UserBloc>(
create: (BuildContext context) => UserBloc(UserRepository(),pageNo),
),
],
child: Scaffold(
appBar: AppBar(title: const Text('The BloC App')),
body: blocBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
pageNo = "2";
UserBloc(
UserRepository(),pageNo,
).add(LoadUserEvent());
},
child: const Icon(Icons.navigation),
),
),
);
}
Widget blocBody() {
return BlocProvider(
create: (context) => UserBloc(
UserRepository(),pageNo,
)..add(LoadUserEvent()),
child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoadingState) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (state is UserLoadedState) {
List<UserModel> userList = state.users;
return ListView.builder(
itemCount: userList.length,
itemBuilder: (_, index) {
return Padding(
padding:
const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: Card(
color: Theme.of(context).primaryColor,
child: ListTile(
title: Text(
'${userList[index].firstName} ${userList[index].lastName}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'${userList[index].email}',
style: const TextStyle(color: Colors.white),
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
userList[index].avatar.toString()),
))),
);
});
}
if (state is UserErrorState) {
return const Center(
child: Text("Error"),
);
}
return Container();
},
),
);
}
}
用户区块
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository _userRepository;
final String pageNo;
UserBloc(this._userRepository,this.pageNo) : super(UserLoadingState()) {
on<LoadUserEvent>((event, emit) async {
emit(UserLoadingState());
try {
final users = await _userRepository.getUsers(pageNo);
emit(UserLoadedState(users));
} catch (e) {
emit(UserErrorState(e.toString()));
}
});
}
}
用户事件
@immutable
abstract class UserEvent extends Equatable {
const UserEvent();
}
class LoadUserEvent extends UserEvent {
@override
List<Object?> get props => [];
}
用户状态
@immutable
abstract class UserState extends Equatable {}
//data loading state
class UserLoadingState extends UserState {
@override
List<Object?> get props => [];
}
class UserLoadedState extends UserState {
final List<UserModel> users;
UserLoadedState(this.users);
@override
List<Object?> get props => [users];
}
class UserErrorState extends UserState {
final String error;
UserErrorState(this.error);
@override
List<Object?> get props => [error];
}
用户模型
class UserModel {
int? id;
String? email;
String? firstName;
String? lastName;
String? avatar;
UserModel({this.id, this.email, this.firstName, this.lastName, this.avatar});
UserModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
email = json['email'];
firstName = json['first_name'];
lastName = json['last_name'];
avatar = json['avatar'];
}
}
用户存储库
class UserRepository {
String userUrl = 'https://reqres.in/api/users?page=';
Future<List<UserModel>> getUsers(String pageNo) async {
Response response = await get(Uri.parse(userUrl+pageNo));
if (response.statusCode == 200) {
final List result = jsonDecode(response.body)['data'];
return result.map((e) => UserModel.fromJson(e)).toList();
} else {
throw Exception(response.reasonPhrase);
}
}
}
第一个问题是使用新的
UserRepository
存储库创建新的块实例。如果您愿意,您可以创建单例类。
要访问当前的块实例,您可以使用
BlocProvider.of<UserBloc>(context);
。
final bloc = BlocProvider.of<UserBloc>(context);
bloc.add(LoadUserEvent());
您无法访问与您创建的块相同的上下文。您可以使用 Builder 或新的小部件来实现单独的上下文。
现在,当我们获取数据时,旧数据会被新数据替换,而不是扩展列表。因此我正在修改块,例如
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository _userRepository;
final String pageNo; //I prefer using event for this.
UserBloc(this._userRepository, this.pageNo) : super(UserLoadingState()) {
on<LoadUserEvent>((event, emit) async {
// emit(UserLoadingState()); //not needed, else we need to lift up the old user list
debugPrint("pageNo $pageNo");
try {
final users = await _userRepository.getUsers(pageNo);
List<UserModel> oldUser = []; //get the old user list
if (state is UserLoadedState) {
oldUser = (state as UserLoadedState).users;
debugPrint("oldUser.length ${oldUser.length}");
}
emit(UserLoadedState([...oldUser, ...users]));
} catch (e) {
emit(UserErrorState(e.toString()));
}
});
}
}
完整片段
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:http/http.dart';
import 'dart:convert';
import 'package:equatable/equatable.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
String pageNo = "1";
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<UserBloc>(
create: (BuildContext context) => UserBloc(UserRepository(), pageNo)
..add(LoadUserEvent()), //initially load the user
),
],
child: Builder(
builder: (context) {
/// you cant directly access the bloc from here, so use builder or new widget
return Scaffold(
appBar: AppBar(title: const Text('The BloC App')),
body: blocBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
final bloc = BlocProvider.of<UserBloc>(context);
var pageNo = "2";
bloc.add(LoadUserEvent());
},
child: const Icon(Icons.navigation),
),
);
},
),
);
}
Widget blocBody() {
return BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoadingState) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (state is UserLoadedState) {
List<UserModel> userList = state.users;
debugPrint("userList.length ${userList.length}");
return ListView.builder(
itemCount: userList.length,
itemBuilder: (_, index) {
return Padding(
padding:
const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: Card(
color: Theme.of(context).primaryColor,
child: ListTile(
title: Text(
'${userList[index].firstName} ${userList[index].lastName}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'${userList[index].email}',
style: const TextStyle(color: Colors.white),
),
leading: CircleAvatar(
// backgroundImage:
// NetworkImage(userList[index].avatar.toString()),
),
),
),
);
});
}
if (state is UserErrorState) {
return const Center(
child: Text("Error"),
);
}
return Container();
},
);
}
}
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepository _userRepository;
final String pageNo;
UserBloc(this._userRepository, this.pageNo) : super(UserLoadingState()) {
on<LoadUserEvent>((event, emit) async {
// emit(UserLoadingState()); //not needed, else we need to lift up the old user list
debugPrint("pageNo $pageNo");
try {
final users = await _userRepository.getUsers(pageNo);
List<UserModel> oldUser = []; //get the old user list
if (state is UserLoadedState) {
oldUser = (state as UserLoadedState).users;
debugPrint("oldUser.length ${oldUser.length}");
}
emit(UserLoadedState([...oldUser, ...users]));
} catch (e) {
emit(UserErrorState(e.toString()));
}
});
}
}
@immutable
abstract class UserEvent extends Equatable {
const UserEvent();
}
class LoadUserEvent extends UserEvent {
@override
List<Object?> get props => [];
}
@immutable
abstract class UserState extends Equatable {}
//data loading state
class UserLoadingState extends UserState {
@override
List<Object?> get props => [];
}
class UserLoadedState extends UserState {
final List<UserModel> users;
UserLoadedState(this.users);
@override
List<Object?> get props => [users];
}
class UserErrorState extends UserState {
final String error;
UserErrorState(this.error);
@override
List<Object?> get props => [error];
}
class UserModel { //also prefer extending Equatable
int? id;
String? email;
String? firstName;
String? lastName;
String? avatar;
UserModel({this.id, this.email, this.firstName, this.lastName, this.avatar});
UserModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
email = json['email'];
firstName = json['first_name'];
lastName = json['last_name'];
avatar = json['avatar'];
}
}
class UserRepository {
String userUrl = 'https://reqres.in/api/users?page=';
Future<List<UserModel>> getUsers(String pageNo) async {
// Response response = await get(Uri.parse(userUrl+pageNo));
//
// if (response.statusCode == 200) {
// final List result = jsonDecode(response.body)['data'];
// return result.map((e) => UserModel.fromJson(e)).toList();
// } else {
// throw Exception(response.reasonPhrase);
// }
return List.generate(
3,
(index) => UserModel(
id: index,
email: "email",
firstName: "firstName",
lastName: "lastName",
avatar: "avatar"));
}
}