在事件处理程序正常完成块错误后,如何解决发出被调用的问题?

Posted

技术标签:

【中文标题】在事件处理程序正常完成块错误后,如何解决发出被调用的问题?【英文标题】:How to resolve emit was called after an event handler completed normally bloc error? 【发布时间】:2021-12-02 08:57:48 【问题描述】:

我正在使用颤振块显示下载进度百分比,但我一直遇到这个问题。我认为问题出现在 onDone 方法中,但我不知道如何解决它。

错误:

发生了异常。 _AssertionError ('package:bloc/src/bloc.dart': 断言失败: line 137 pos 7: '!_isCompleted': 在事件处理程序正常完成后调用发出。 这通常是由于事件处理程序中没有等待的未来。 请确保使用事件处理程序等待所有异步操作 并在调用 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));
  



【问题讨论】:

【参考方案1】:

如果像这样将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'));
  

【讨论】:

以上是关于在事件处理程序正常完成块错误后,如何解决发出被调用的问题?的主要内容,如果未能解决你的问题,请参考以下文章

delphi多线程怎么解决数据处理速度跟不上数据接收的速度?

Flex 的 FileReference.save() 只能在用户事件处理程序中调用——我该如何解决这个问题?

XP事件ID分别为:1002、1、17、29,显示错误,如何找到这些错误事件对应的服务?

发出调用快速完成处理程序关闭的问题

导入时保存所有内容之前的 MagicalRecord 完成块

如何从事件处理程序返回任务?