我使用这些软件包来处理以下代码:flutter_bloc、oxidized、freezed和get_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;
}
型
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()));
}
型
主.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
关联,如何修复它?
2条答案
按热度按时间ttcibm8c1#
你将
_runEvent
声明为async
,并返回void
而不是Future<>
。这通常是一个不好的模式,因为这个函数的调用者不知道它的异步特性,不能将结果await
。字符串
如果将
void
更改为适当的Future<>
,BloC应该能够等待调用并避免任何竞争条件flseospp2#
我做了这些改变,它像魅力一样工作:
tmdb_cubit.dart(* 将Bloc替换为Cubit*)
字符串
home_screen.dart
型
主.dart
型