Flutter整洁架构+Cubit下实现网络状态监听流的方案咨询
问题描述
我基于**Clean Architecture(整洁架构)**和Cubit搭建了Flutter项目,在core/network目录下实现了NetworkInfo类,通过Future方法检测网络连接,目前在RepositoryImpl中使用正常。但我需要添加网络状态监听stream以持续检测网络状态,不清楚应在哪个层级编写代码,以及如何在不违反整洁架构原则、保证可测试性的前提下结合Cubit使用streams?
现有代码
NetworkInfo 抽象类与实现
abstract class NetworkInfo { Future<bool> isConnected(); } class NetworkInfoImpl implements NetworkInfo { InternetConnection internetConnection; NetworkInfoImpl({ required this.internetConnection, }); @override Future<bool> isConnected() { // TODO: implement isConnected return internetConnection.hasInternetAccess; } }
AuthRepositoryImpl
class AuthRepositoryImpl implements AuthRepository { final AuthRemoteDatasource authRemoteDatasource; final NetworkInfo networkInfo; AuthRepositoryImpl({ required this.authRemoteDatasource, required this.networkInfo, required this.crashLog, }); @override ResultFuture<User> emailPasswordLogin({ required String email, required String password, }) async { // TODO: implement emailPasswordLogin try { if (!await networkInfo.isConnected()) { return const Result.error(NoInternetFailure()); } var user = await authRemoteDatasource.emailPasswordLogin( email: email, password: password, ); return Result.success(user); } on AuthException { return const Result.error(AuthFailure()); } catch (exception, stack) { return Result.error(UnknownFailure()); } } }
解决方案
1. 扩展NetworkInfo抽象层(核心层)
按照整洁架构的要求,抽象定义必须放在核心层。我们给NetworkInfo添加网络状态监听的stream接口,这样既保持核心层的抽象性,又能让实现类提供具体的流能力,不依赖外部库。
修改后的抽象类:
abstract class NetworkInfo { Future<bool> isConnected(); // 添加网络状态变化的stream接口 Stream<bool> get connectionStatusStream; }
2. 在NetworkInfoImpl中实现Stream逻辑
在core/network的实现类里,基于你使用的InternetConnection库实现stream。如果库本身不支持监听,也可以用定期检测的方式生成stream:
class NetworkInfoImpl implements NetworkInfo { final InternetConnection internetConnection; // 可选:自定义检测周期 final Duration checkInterval; NetworkInfoImpl({ required this.internetConnection, this.checkInterval = const Duration(seconds: 5), }); @override Future<bool> isConnected() { return internetConnection.hasInternetAccess; } @override Stream<bool> get connectionStatusStream { // 方式1:如果库自带监听stream,直接返回 // return internetConnection.connectionStatusStream; // 方式2:定期检测实现(适配无自带stream的库) return Stream.periodic(checkInterval, (_) async => await isConnected()) .asyncMap((future) => future) // 过滤重复状态,避免频繁触发UI更新 .distinct(); } }
3. 分层职责划分:Stream处理放在Presentation层
网络状态属于全局UI状态(比如显示离线提示),不属于Repository的业务逻辑范畴。根据整洁架构,持续状态监听应该交给Presentation层的Cubit管理,Repository只负责单次业务操作前的网络检测。
4. 实现NetworkCubit(Presentation层)
创建专门的NetworkCubit订阅网络状态stream,统一管理网络状态并通知UI,既符合单一职责,也方便测试:
import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import '../../core/network/network_info.dart'; // 网络状态实体类 class NetworkState extends Equatable { final bool isConnected; const NetworkState({required this.isConnected}); @override List<Object> get props => [isConnected]; } class NetworkCubit extends Cubit<NetworkState> { final NetworkInfo networkInfo; StreamSubscription? _networkSubscription; NetworkCubit({required this.networkInfo}) : super(const NetworkState(isConnected: false)) { _startListening(); } void _startListening() { _networkSubscription = networkInfo.connectionStatusStream.listen((isConnected) { emit(NetworkState(isConnected: isConnected)); }); } // 手动触发一次网络检测(比如UI主动刷新) Future<void> checkConnection() async { final isConnected = await networkInfo.isConnected(); emit(NetworkState(isConnected: isConnected)); } @override Future<void> close() { _networkSubscription?.cancel(); return super.close(); } }
5. UI层使用NetworkCubit
通过BlocListener或BlocBuilder监听状态变化,实现UI层面的离线提示等逻辑:
BlocListener<NetworkCubit, NetworkState>( listener: (context, state) { if (!state.isConnected) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("当前无网络连接")), ); } }, child: // 你的UI内容 )
6. 保证可测试性的关键
- 始终依赖
NetworkInfo抽象类,测试时可以mock这个类,返回自定义的stream来模拟网络状态变化。 - 测试
NetworkCubit时,通过mockNetworkInfo的connectionStatusStream,验证Cubit是否正确emit对应状态。 - Repository层保持原有逻辑不变,只负责单次网络检测,不需要处理stream,避免职责混淆。
内容的提问来源于stack exchange,提问作者user22969480
相关产品推荐
相关产品推荐

