You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Resocoder的Clean Architecture:UI如何感知外部数据源变更?

关于Resocoder Clean Architecture中UI接收外部数据源变更的实现方案

Resocoder的这套Flutter Clean Architecture变体完全支持UI接收外部数据源(比如API主动推送)的变更通知,核心是利用Dart的Stream(或RxDart的响应式工具)在各层间传递数据流,同时不破坏分层依赖规则。具体实现路径如下:

1. 数据层监听外部变更

在数据层的Remote Data Source中,直接对接外部数据源的推送机制:

  • 如果是WebSocket、Firebase实时数据库这类主动推送的服务,在这里建立长连接并监听数据变更事件;
  • 如果是需要轮询的REST API,也可以在这里通过Stream.periodic实现定时拉取。
  • 当收到新数据后,将其解析为Domain层定义的Entity,通过Stream输出。

示例伪代码:

class UserRemoteDataSource {
  Stream<User> listenToUserUpdates() {
    // 模拟WebSocket监听用户数据变更
    return WebSocketChannel.connect(Uri.parse('wss://api.example.com/user'))
        .stream
        .map((event) => User.fromJson(jsonDecode(event)));
  }
}

2. Repository层暴露标准化数据流

Repository作为数据层和Domain层的中间层,将数据源的Stream封装后,按照Domain层定义的抽象接口暴露给上层:

abstract class UserRepository {
  Stream<User> getUserUpdates();
}

class UserRepositoryImpl implements UserRepository {
  final UserRemoteDataSource remoteDataSource;

  UserRepositoryImpl(this.remoteDataSource);

  @override
  Stream<User> getUserUpdates() {
    return remoteDataSource.listenToUserUpdates();
  }
}

3. Presentation层订阅并转换状态

在ViewModel/Cubit(Presentation层)中,订阅Repository的Stream,当收到新数据时,转换为对应的UI状态并emit:

class UserCubit extends Cubit<UserState> {
  final UserRepository userRepository;
  StreamSubscription? _subscription;

  UserCubit(this.userRepository) : super(UserInitial()) {
    _listenToUserUpdates();
  }

  void _listenToUserUpdates() {
    _subscription = userRepository.getUserUpdates().listen((user) {
      emit(UserLoaded(user));
    });
  }

  @override
  Future<void> close() {
    _subscription?.cancel();
    return super.close();
  }
}

abstract class UserState {}
class UserInitial extends UserState {}
class UserLoaded extends UserState {
  final User user;
  UserLoaded(this.user);
}

4. UI层监听状态自动刷新

UI组件通过BlocBuilder(或StreamBuilder)监听Presentation层的状态变化,当状态更新时自动重建UI:

BlocBuilder<UserCubit, UserState>(
  builder: (context, state) {
    if (state is UserLoaded) {
      return Text('当前用户:${state.user.name}');
    } else {
      return const CircularProgressIndicator();
    }
  },
)

补充说明

如果是普通REST API的被动场景(比如需要主动拉取同步数据),可以在Presentation层定时调用Use Case获取最新数据,同样通过状态更新触发UI刷新,本质逻辑和主动推送一致。

这套实现完全符合Clean Architecture的依赖规则:外层(UI、Presentation)依赖内层(Domain、Data)的抽象,数据流从最外层的数据源逐步向上传递到UI,没有打破分层边界。

内容的提问来源于stack exchange,提问作者John Andersen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 21:35:34