我将这些包用于以下代码:flutter_blocoxidizedfreezedget_it

tmdb_bloc.dart

typedef TmdbState = PageState<List<MovieEntity>>;

class TmdbBloc extends Bloc<TmdbEvent, TmdbState> {
  final TmdbPublicUseCases useCases;

  TmdbBloc(this.useCases) : super(const PageState.initial()) {
    on<TmdbEvent>((event, emit) async {
      event.map(
        getPopularMovies: (_) => _runEvent(emit, useCases.proxy.getPopularMovies),
        getTrendingMovies: (_) => _runEvent(emit, useCases.proxy.getTrendingMovies),
        searchMovies: (e) => _runEvent(emit, () => useCases.proxy.searchMovies(e.query)),
      );
    });
  }

  void _runEvent(Emitter<TmdbState> emit, Future<TMovieListResult> Function() caller) async {
    emit(const PageState.loading());
    final response = await caller();
    response.when(
      ok: (list) => emit(PageState.loaded(list)), 
      err: (error) => emit(PageState.error(error.message)),
    );
  }
}

tmdb_events.dart

part 'tmdb_events.freezed.dart';

@freezed
sealed class TmdbEvent with _$TmdbEvent {
  const factory TmdbEvent.getPopularMovies() = PopularMoviesEvent;
  const factory TmdbEvent.getTrendingMovies() = TrendingMoviesEvent;
  const factory TmdbEvent.searchMovies(String query) = SearchMoviesEvent;
}

page_states.dart

part 'page_states.freezed.dart';

@freezed
sealed class PageState<T extends Object> with _$PageState {
  const factory PageState.initial() = InitialState;
  const factory PageState.loading() = LoadingState;
  const factory PageState.loaded(T data) = LoadedState;
  const factory PageState.error([String? message]) = ErrorState;
}

di.dart

final sl = GetIt.instance;

void getItInit() {
  // external connector
  sl.registerLazySingleton<TApiDataSourceClient>(() => DioClient());
  // data sources
  sl.registerLazySingleton<TBaseApiClient>(() => RestApiClient(sl()));
  sl.registerLazySingleton<TBaseDataProxy>(() => DataProxy(sl()));
  // use cases
  sl.registerLazySingleton(() => TmdbPublicUseCases(sl()));
}

main.dart

void main() async {
  await TMDB.init();
  getItInit();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: BlocProvider(
        create: (_) => TmdbBloc(sl<TmdbPublicUseCases>())..add(const TmdbEvent.getPopularMovies()),
        child: const HomeScreen(),
      ),
    );
  }
}

home_screen.dart

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _buildAppBar(),
      body: Container(
        color: Colors.black,
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildDefaultImage(),
              const SizedBox(height: 30),
              const Text(
                'Popular Movies',
                style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
              ),
              BlocBuilder<TmdbBloc, TmdbState>(
                builder: (context, state) {
                  return state.when(
                    initial: () => const Text('No data to show'), 
                    loading: () => const CircularProgressIndicator(), 
                    loaded: (list) => Text(list.runtimeType.toString()), 
                    error: (e) => Text('Something went wrong: $e'),
                  );
                },
              ),
              const SizedBox(height: 20),
            ],
          ),
        ),
      ),
    );
  }
  ...
}

运行我的应用程序后,它一直在调试控制台中显示CircularProgressIndicator小部件,其中包含以下文本:

Launching lib/main.dart on sdk gphone64 x86 64 in debug mode...
✓  Built build/app/outputs/flutter-apk/app-debug.apk.
E/flutter ( 4527): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:bloc/src/emitter.dart': Failed assertion: line 114 pos 7: '!_isCompleted':
E/flutter ( 4527):
E/flutter ( 4527): emit was called after an event handler completed normally.
E/flutter ( 4527): This is usually due to an unawaited future in an event handler.
E/flutter ( 4527): Please make sure to await all asynchronous operations with event handlers
E/flutter ( 4527): and use emit.isDone after asynchronous operations before calling emit() to
E/flutter ( 4527): ensure the event handler has not completed.
E/flutter ( 4527):
E/flutter ( 4527):   **BAD**
E/flutter ( 4527):   on<Event>((event, emit) {
E/flutter ( 4527):     future.whenComplete(() => emit(...));
E/flutter ( 4527):   });
E/flutter ( 4527):
E/flutter ( 4527):   **GOOD**
E/flutter ( 4527):   on<Event>((event, emit) async {
E/flutter ( 4527):     await future.whenComplete(() => emit(...));
E/flutter ( 4527):   });
E/flutter ( 4527):
E/flutter ( 4527): #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
E/flutter ( 4527): #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
E/flutter ( 4527): #2      _Emitter.call (package:bloc/src/emitter.dart:114:7)
E/flutter ( 4527): #3      TmdbBloc._runEvent.<anonymous closure> (package:movie_app_tdd_di/features/tmdb_public/3_presentation/1_bloc/tmdb_bloc.dart:27:25)
E/flutter ( 4527): #4      Ok.when (package:oxidized/src/result.dart:264:75)
E/flutter ( 4527): #5      TmdbBloc._runEvent (package:movie_app_tdd_di/features/tmdb_public/3_presentation/1_bloc/tmdb_bloc.dart:26:14)
E/flutter ( 4527): <asynchronous suspension>
E/flutter ( 4527):
D/EGL_emulation( 4527): app_time_stats: avg=18.48ms min=5.36ms max=91.61ms count=44
D/EGL_emulation( 4527): app_time_stats: avg=13.80ms min=5.36ms max=31.71ms count=61
D/EGL_emulation( 4527): app_time_stats: avg=7.21ms min=3.08ms max=12.55ms count=60
D/EGL_emulation( 4527): app_time_stats: avg=14.61ms min=9.96ms max=26.73ms count=60
D/EGL_emulation( 4527): app_time_stats: avg=16.67ms min=10.15ms max=22.99ms count=61
D/EGL_emulation( 4527): app_time_stats: avg=16.73ms min=14.36ms max=18.81ms count=60
D/EGL_emulation( 4527): app_time_stats: avg=18.50ms min=5.40ms max=100.80ms count=54
D/EGL_emulation( 4527): app_time_stats: avg=8.58ms min=3.11ms max=27.14ms count=61
Application finished.

Exited.

我不知道发生了什么,我认为我的TmdbBloc类是正确的.

关于此代码:

              BlocBuilder<TmdbBloc, TmdbState>(
                builder: (context, state) {
                  return state.when(
                    initial: () => const Text('No data to show'), 
                    loading: () => const CircularProgressIndicator(), 
                    loaded: (list) => Text(list.runtimeType.toString()), 
                    error: (e) => Text('Something went wrong: $e'),
                  );
                },
              ),

我认为它的定义不正确,因为它没有指示特定的相关事件.如果该代码段与TmdbEvent.getPopularMovies()PopularMoviesEvent相关联,该如何修复?

推荐答案

我做了这些改变,它的效果很好:

tmdb_cubit.dart(Replaced Bloc with Cubit)

typedef TmdbState = PageState<List<MovieEntity>>;


sealed class TmdbCubit<T extends TmdbEvent> extends Cubit<TmdbState> {
  final TmdbPublicUseCases useCases;

  TmdbCubit(this.useCases) : super(const PageState.initial());

  Future<void> _runEvent(Future<TMovieListResult> Function() caller) async {
    emit(const PageState.loading());

    final response = await caller();

    response.when(
      ok: (list) => emit(PageState.loaded(list)), 
      err: (error) => emit(PageState.error(error.message)),
    );
  }
}

final class PopularMoviesCubit extends TmdbCubit<PopularMoviesEvent> {
  PopularMoviesCubit(super.useCases);
  void call() async => await _runEvent(useCases.proxy.getPopularMovies);
}

final class TrendingMoviesCubit extends TmdbCubit<TrendingMoviesEvent> {
  TrendingMoviesCubit(super.useCases);
  void call() async => await _runEvent(useCases.proxy.getTrendingMovies);
}

final class SearchMoviesCubit extends TmdbCubit<SearchMoviesEvent> {
  SearchMoviesCubit(super.useCases);
  void call(String query) async => await _runEvent(() => useCases.proxy.searchMovies(query));
}

home_screen.dart

...
              BlocBuilder<TrendingMoviesCubit, TmdbState>(
                builder: (context, state) {
                  return state.when(
                    initial: () => const Text('No data to show'), 
                    loading: () => const CircularProgressIndicator(), 
                    loaded: (list) => Text((list as List<MovieEntity>).runtimeType.toString()),
                    error: (e) => Text('Something went wrong: $e'),
                  );
                },
              ),
...

main.dart

....
      home: BlocProvider(
        create: (_) => TrendingMoviesCubit(sl<TmdbPublicUseCases>())..call(),
....

Flutter相关问答推荐

Flutter 导致底部溢出

Flutter 中的面向对象模式

Flutter 对齐:不适用于多行文字

如何组合匹配器

确保通过在CheckIfFavoriteMovieEvent((event,emit){...})上注册处理程序误差

框中的Flutter 适配图像

将Riverpods NotifierProvider与State类一起使用

火焰Flutter 在多个向量之间插补2

按一下按钮即可更新 fl_chart

Flutter:如何在 Future 函数上添加网络判断和 showDialog

如何设置行中项目之间的空格相等?

面对Flutter 中的行和列问题

Flutter/Dart - 从外部类更新状态

在 Flutter 中读取 Firebase 数据库数据时遇到问题

如何在 Flutter 执行通知时运行后台代码?

为什么容器会填满整个空间?

我一直在try 创建按钮以导航到第二页,但不知何故 RaisedButton 功能无法正常工作

将 onSaved(value) 从自定义 TextFormField 小部件传递给另一个?

在自动完成中 Select 值后保持键盘焦点

Flutter Bloc Todo 示例 - 收听存储库中的单个 todo