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

Flutter Bloc中如何访问另一个Bloc的状态?

Flutter Bloc中如何访问另一个Bloc的状态?

下面提供三种实用方案解决MediaBloc获取UserBloc中token的问题:

方案一:构造函数注入UserBloc并监听状态

直接在MediaBloc初始化时传入UserBloc实例,监听其状态变化同步token,后续请求时直接使用同步后的token。

修改MediaBloc代码:

class MediaBloc extends Bloc<MediaEvent, MediaState> {
  final UserBloc userBloc;
  late StreamSubscription<UserState> _userSubscription;
  String? _currentToken;

  MediaBloc(this.userBloc) : super(MediaState(mediaList: [])) {
    // 监听UserBloc状态更新,同步token
    _userSubscription = userBloc.stream.listen((userState) {
      _currentToken = userState.token;
    });

    on<FetchMediaEvent>((event, emit) async {
      if (_currentToken == null) {
        // 处理未登录场景,比如emit带错误的状态
        emit(MediaState(mediaList: [], error: "用户未登录"));
        return;
      }
      List<Media> mediaList = await fetchUserMedia(token: _currentToken!);
      emit(MediaState(mediaList: mediaList));
    });
  }

  @override
  Future<void> close() {
    // 取消订阅,避免内存泄漏
    _userSubscription.cancel();
    return super.close();
  }
}

UI层提供Bloc实例时,通过context.read()获取UserBloc传入MediaBloc:

BlocProvider(
  create: (context) => UserBloc(),
  child: BlocProvider(
    create: (context) => MediaBloc(context.read<UserBloc>()),
    child: YourScreen(),
  ),
)

方案二:在UI层获取token后触发MediaBloc事件

修改FetchMediaEvent让它携带token参数,在UI层触发事件前先从UserBloc获取token。

首先更新事件类:

class FetchMediaEvent {
  final String token;
  FetchMediaEvent(this.token);
}

然后修改MediaBloc的事件处理:

class MediaBloc extends Bloc<MediaEvent, MediaState> {
  MediaBloc() : super(MediaState(mediaList: [])) {
    on<FetchMediaEvent>((event, emit) async {
      List<Media> mediaList = await fetchUserMedia(token: event.token);
      emit(MediaState(mediaList: mediaList));
    });
  }
}

UI层触发事件时先获取token:

ElevatedButton(
  onPressed: () {
    final userState = context.read<UserBloc>().state;
    if (userState.token != null) {
      context.read<MediaBloc>().add(FetchMediaEvent(userState.token!));
    }
  },
  child: const Text("获取媒体列表"),
)

如果需要在UserBloc状态变化时自动触发媒体请求,可用BlocListener:

BlocListener<UserBloc, UserState>(
  listener: (context, state) {
    if (state.token != null) {
      context.read<MediaBloc>().add(FetchMediaEvent(state.token!));
    }
  },
  child: YourScreen(),
)

方案三:通过Repository层共享状态(推荐)

将token抽离到独立的Repository类中,UserBloc负责更新Repository的token,MediaBloc从Repository读取token,彻底解耦两个Bloc。

首先定义Repository:

class AuthRepository {
  String? _token;
  String? get token => _token;

  // 更新token的方法
  void updateToken(String? newToken) {
    _token = newToken;
  }
}

修改UserBloc,注入AuthRepository并更新token:

class UserBloc extends Bloc<UserEvent, UserState> {
  final AuthRepository authRepo;

  UserBloc(this.authRepo) : super(UserState(token: authRepo.token)) {
    // 示例:处理更新token的事件
    on<UpdateUserTokenEvent>((event, emit) {
      authRepo.updateToken(event.token);
      emit(UserState(token: event.token));
    });
  }
}

修改MediaBloc,注入AuthRepository并读取token:

class MediaBloc extends Bloc<MediaEvent, MediaState> {
  final AuthRepository authRepo;

  MediaBloc(this.authRepo) : super(MediaState(mediaList: [])) {
    on<FetchMediaEvent>((event, emit) async {
      final token = authRepo.token;
      if (token == null) {
        emit(MediaState(mediaList: [], error: "用户未登录"));
        return;
      }
      List<Media> mediaList = await fetchUserMedia(token: token);
      emit(MediaState(mediaList: mediaList));
    });
  }
}

最后在App顶层提供Repository和Bloc:

RepositoryProvider(
  create: (context) => AuthRepository(),
  child: BlocProvider(
    create: (context) => UserBloc(context.read<AuthRepository>()),
    child: BlocProvider(
      create: (context) => MediaBloc(context.read<AuthRepository>()),
      child: YourApp(),
    ),
  ),
)

内容的提问来源于stack exchange,提问作者shakky goyal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:35:02