我在存储库中有一个方法,它在调用时从 api 获取一些数据。该方法可以从两个、三个或更多块调用。因此,为了优化 api 调用,该方法应该只被调用一次,并且这三个块应该得到结果。
根据 bloc 文档和here提供的示例,我已将存储库方法更改为如下所示的流:
Stream<UserInfo> getUserInfo(
{required String userKey, required String caller}) async* {
print("Repo Caller is $caller");
UserInforesponse =
await provider.getUserInfo(
patientKey: patientKey,
);
yield response;
}
在需要此方法结果的块中,我这样做:
await emit.forEach(
repo.getUserInfo(userKey: userKey,caller:"bloc1"),
onData: (UserInfo response) {
print("bloc1 got data");
return state.copyWith( ... );
},
);
在块 2 ,3 ... 中使用相同的方法:
await emit.forEach(
repo.getUserInfo(userKey: userKey,caller:"bloc2"),
onData: (UserInfo response) {
print("bloc2 got data");
return state.copyWith( ... );
},
);
但问题是这些区块没有监听一个流。他们正在创建自己的个人流。因此,结果会打印在输出中:
Repo Caller is bloc1
Repo Caller is bloc2
所以 api 服务被调用两次,如果我需要这个 api 结果在 5 个块中,它将被调用 5 次而不是一次。 由于文档中的示例未涵盖这种情况,我怎样才能实现预期的行为。
来自
forEach
中的emmiter
方法的文档:
/// Subscribes to the provided [stream] and invokes the [onData] callback
/// when the [stream] emits new data and the result of [onData] is emitted.
/// .....
Future<void> forEach<T>(...
下一个问题是:如何创建存储库实例以及如何将其提供/注入到块中 - 它是同一个实例吗? 作为一种选择,在您的集团中,您可以做一些常见的事情,如下所示:
class Bloc1 extends Bloc<SomeEvent, SomeState> {
final YourRepository _yourRepository
final StreamSubscription _subscription;
Bloc1(YourRepository yourRepository) :
_yourRepository = yourRepository,
super(UserState.initial()) {
...
_subscription = _yourRepository.userInfoStream.listen((userInfo){
emit(state.copyWith(...));
}, onError: (error) {
emit(state.copyWith(...));
});
...
}
void getUserInfo(
required String userKey,
required String caller,
){
_yourRepository.getUserInfo(userKey, caller);
}
@override
Future<void> close() {
_subscription?.cancel();
return super.close();
}
}
...
在你的仓库中是这样的:
class YourRepository{
final _userInfoController = StreamController<List<int>>.broadcast();
Stream<UserInfo> get userInfoStream => _userInfoController.stream;
void getUserInfo({
required String userKey,
required String caller,
}) async* {
final userInforesponse = await provider.getUserInfo(
patientKey: patientKey,
);
_userInfoController.add(userInforesponse);
}
void dispose() {
_userInfoController.close();
}
}