如何解决事件处理程序正常完成后调用emit块错误?

问题描述 投票:0回答:5

我正在使用 flutter bloc 来显示下载进度百分比,但我不断遇到这个问题。我认为问题出现在

onDone
方法中,但我不知道如何解决它。

错误:

发生异常。 _AssertionError ('package:bloc/src/bloc.dart': 断言失败: 第 137 行 pos 7: '!_isCompleted': 事件处理程序正常完成后调用emit。 这通常是由于事件处理程序中未等待的 future 造成的。 请确保使用事件处理程序等待所有异步操作 并在异步操作之后调用emit()之前使用emit.isDone 确保事件处理程序尚未完成。

不好

 on<Event>((event, emit) {
    future.whenComplete(() => emit(...));
  });

  on<Event>((event, emit) async {
    await future.whenComplete(() => emit(...));
  });
)

代码:


import 'package:bloc/bloc.dart';
import 'package:download_progress_with_bloc/downlaod_file.dart';
import 'package:download_progress_with_bloc/download_event.dart';
import 'package:download_progress_with_bloc/download_state.dart';
import 'package:download_progress_with_bloc/permission_handler.dart';
import 'package:download_progress_with_bloc/store_book_repo.dart';
import 'package:http/http.dart' as http;

class DownloadBloc extends Bloc<DownloadEvent, DownloadState> {
  DownloadBloc({required this.storeBookRepo}) : super(DownloadInitial()) {
    on<DownloadStarted>(onStarted);
    on<DownloadProgressed>(onProgressed);
  }
  final StoreBookRepo storeBookRepo;

  http.StreamedResponse? response;
  // StreamController? _controller;
  int received = 0;
  List<int> bytes = [];
  int totalSize = 0;

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

  Future<void> onStarted(
      DownloadStarted event, Emitter<DownloadState> emit) async {
    try {
      await PermissionHandler.requestStoragePermission();
      response = await downloadFile();
      totalSize = response!.contentLength ?? 0;
      emit(DownloadInProgress(progress: received, totalSize: totalSize));
      response?.stream.asBroadcastStream().listen((value) async {
        received += value.length;
        bytes.addAll(value);
        add(DownloadProgressed(progress: received));
        print('received value is $received');
      }).onDone(
        () async {
          await storeBookRepo
              .storePdf(
                bytes.toString(),
                bookTitle: 'bookTitle',
              )
              .then((value) => emit(DownloadCompleted()));
          // emit(DownloadCompleted());
        },
      );
    } catch (e) {
      emit(DownlaodFailed(errorMessage: '$e'));
    }
  }

  void onProgressed(DownloadProgressed event, Emitter<DownloadState> emit) {
    emit(DownloadInProgress(progress: event.progress, totalSize: totalSize));
  }


}
flutter dart state bloc
5个回答
13
投票

如果像这样将

listen
重写为
await for
会怎样?

Future<void> onStarted(
  DownloadStarted event,
  Emitter<DownloadState> emit,
) async {
  try {
    await PermissionHandler.requestStoragePermission();
    response = await downloadFile();
    totalSize = response!.contentLength ?? 0;

    emit(DownloadInProgress(
      progress: received,
      totalSize: totalSize,
    ));

    await for (final value in response?.stream) {
      received += value.length;
      bytes.addAll(value);

      add(DownloadProgressed(progress: received));
      print('received value is $received');
    }

    await storeBookRepo.storePdf(
      bytes.toString(),
      bookTitle: 'bookTitle',
    );

    emit(DownloadCompleted());
  } catch (e) {
    emit(DownlaodFailed(errorMessage: '$e'));
  }
}

4
投票

async
块之前使用
on
,并在未来操作中使用
await

on<NumberTriviaEvent>((event, emit) async {
   await Future func(){
     //some time consuming operation like fetch data
   }
   emit(YourState())  
}

4
投票

我也有这个错误

在我的例子中,当使用 Flutter_Bloc 和 Freezed 时,如果你使用了 event.when() 等,你必须像这样等待 event.when 并在使用 wait 时在每个事件中添加异步

    Future<void> _onAddSection(
    SectionEvent event,
    Emitter<SectionState> emit,
  ) async {
    await event.whenOrNull(
      addSection: (sectionViewModel, chapterName) async {
        emit(const SectionState.loading());
        final section =
            _sectionMapper.convert<SectionViewModel, Section>(sectionViewModel);
        final result =
            await _sectionRepository.addSection(section, chapterName);
        result.fold(
          (failure) => emit(SectionState.failure(message: failure.message)),
          (data) => emit(SectionState.success(message: data)),
        );
      },
    );
  }

0
投票

你应该使用 async 和 wait ,很清楚。 但为什么? 在每个 on() 方法完成运行之前,您可以使用 emeeer.之后该集团将处置或取消该发射器。


0
投票

对于未使用 Streams 遇到此问题的任何人,以下是包含解决方案的 GitHub 问题线程:

https://github.com/felangel/bloc/issues/2961#issuecomment-973109283

© www.soinside.com 2019 - 2024. All rights reserved.