我正在嘗試使用顫振塊制作應用程式,但我遇到了 BlocListener 沒有被呼叫的問題,我無法弄清楚我做錯了什么。
這是重現我的問題的最小代碼:
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => AuthBloc(),
child: const AppView(),
);
}
}
/**************** APP VIEW **************/
class AppView extends StatefulWidget {
const AppView({Key? key}) : super(key: key);
@override
State<AppView> createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final _navigatorKey = GlobalKey<NavigatorState>();
NavigatorState get _navigator => _navigatorKey.currentState!;
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navigatorKey,
builder: (context, child) {
print('App builder');
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
print('Bloc listener');
switch (state.status) {
case AuthStatus.authenticated:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Home'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.unauthenticated));
},
child: const Text('Log out'),
),
],
),
);
},
),
(route) => false,
);
break;
default:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Login'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.authenticated));
},
child: const Text('Log in'),
),
],
),
);
},
),
(route) => false,
);
break;
}
},
child: child,
);
},
onGenerateRoute: (_) => MaterialPageRoute(
builder: (context) {
return const Center(
child: Text('splash'),
);
},
),
);
}
}
/**************** AUTH BLOC CLASSES **************/
/**************** AUTH State **************/
enum AuthStatus { unknown, unauthenticated, authenticated }
class AuthState extends Equatable {
final AuthStatus status;
const AuthState._({
this.status = AuthStatus.unknown,
});
const AuthState.unknown() : this._();
const AuthState.authenticated() : this._(status: AuthStatus.authenticated);
const AuthState.unauthenticated()
: this._(status: AuthStatus.unauthenticated);
@override
List<Object?> get props => [status];
}
/**************** AUTH Event **************/
abstract class AuthEvent extends Equatable {
const AuthEvent();
@override
List<Object> get props => [];
}
class AuthStatusChanged extends AuthEvent {
final AuthStatus status;
const AuthStatusChanged(this.status);
@override
List<Object> get props => [status];
}
/**************** AUTH BLOC **************/
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(const AuthState.unknown()) {
print('Bloc constructor');
on<AuthStatusChanged>(_onAuthStatusChanged);
}
_onAuthStatusChanged(
AuthStatusChanged event,
Emitter<AuthState> emit,
) async {
switch (event.status) {
case AuthStatus.unauthenticated:
return emit(const AuthState.unauthenticated());
case AuthStatus.authenticated:
return emit(const AuthState.authenticated());
default:
return emit(const AuthState.unknown());
}
}
}
當我啟動應用程式時,我希望 BlocListener 被呼叫一次,但它位于啟動頁面上。
我使用本教程生成此代碼:https ://bloclibrary.dev/#/flutterlogintutorial
編輯:謝謝大家的洞察力,我不明白 BlocListener 不會在 initialState 上觸發事件(我猜是 RTFM xD)。回顧我使用的教程,這是由“存盤庫”處理的,該存盤庫提供一個延遲創建的流,并且 Bloc 正在偵聽該流以觸發狀態事件的更改。重用相同的概念對我有用!
uj5u.com熱心網友回復:
BlocListener 僅在狀態更改時觸發。在應用程式加載時,您可能希望觸發一個 bloc 事件來更改 AuthBloc 狀態。這可以通過在 initState() 函式中添加一個 bloc 事件并放置一個斷點來查看偵聽器是否被觸發來實作。
https://pub.dev/documentation/flutter_bloc/latest/flutter_bloc/BlocListener-class.html
uj5u.com熱心網友回復:
偵聽器僅在狀態更改后呼叫,在AuthBloc創建后不會呼叫。
還有一個提示:context.read<AuthBloc>().add(const AuthStatusChanged(AuthStatus.authenticated)); 不要那樣做。更喜歡在你的 bloc 實體中創建將觸發事件的方法,它使你的代碼更容易測驗,如果添加very_good_analysis到你的專案中,這是一個由 VGV(flutter bloc 背后的同一家公司)構建的 linter,你會看到有一個 lint 規則反對。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/467976.html
