I'm implementing Bloc pattern for my application and I have to show SnackBar which shows error message when login is unauthenticated.
But I cannot show SnackBar during building phase of widget. I looked for lots of solutions, but I couldn't found.
What is the most efficient way to use this function?
My code
import 'package:chat_app/auth/auth_bloc.dart';
import 'package:chat_app/auth/auth_state.dart';
import 'package:chat_app/main_page.dart';
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Chat App',
      home: MyApp(),
      debugShowCheckedModeBanner: false,
    );
  }
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  final AuthBloc _bloc = AuthBloc();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  @override
    void dispose() {
      _emailController.dispose();
      _passwordController.dispose();
      _bloc.dispose();
      super.dispose();
    }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text('Chat Example')),
      body: StreamBuilder(
          initialData: AuthInitializing(),
          stream: _bloc.authStream,
          builder: (BuildContext context, AsyncSnapshot<AuthState> snapshot){
            AuthState state = snapshot.data;
            if(state is AuthUnauthenticated){
              _showErrorMessage(state.errorMessage);
            }
            if(state is AuthAuthenticated){
              _moveNextPage(context);
            }
            return Form(
              key: _formKey,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20.0),
                child: Column(
                  children: <Widget>[
                    TextFormField(
                      controller: _emailController,
                      keyboardType: TextInputType.emailAddress,
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: '이메일',
                      ),
                    ),
                    SizedBox(height: 20.0),
                    TextFormField(
                      controller: _passwordController,
                      keyboardType: TextInputType.text,
                      obscureText: true,
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: '비밀번호'
                      ),
                    ),
                    SizedBox(height: 20.0),
                    RaisedButton(
                      child: Text('로그인',style: TextStyle(color: Colors.white),),
                      onPressed: () => _bloc.addLoginData(_emailController.text, _passwordController.text),
                      color: Theme.of(context).primaryColor,
                    ),
                    SizedBox(height: 15.0),
                    state is AuthLoading ? _progressBar() : Container()
                  ],
                ),
              ),
            );
          },
        ),
    );
  }
  void _showErrorMessage(String message){
    _scaffoldKey.currentState.showSnackBar(SnackBar(
      content: Text(message),
    ));
  }
  void _moveNextPage(BuildContext context) {
    Navigator.pushReplacement(context, MaterialPageRoute(
      builder: (_) => MainPage()
    ));
  }
  Widget _progressBar() {
    return Center(
      child: CircularProgressIndicator(),
    );
  }
}
StackTrace
I/flutter (30505): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (30505): The following assertion was thrown building StreamBuilder(dirty, state: I/flutter (30505): _StreamBuilderBaseState>#bd8b2): I/flutter (30505): setState() or markNeedsBuild() called during build. I/flutter (30505): This Scaffold widget cannot be marked as needing to build because the framework is already in the I/flutter (30505): process of building widgets. A widget can be marked as needing to be built during the build phase I/flutter (30505): only if one of its ancestors is currently building. This exception is allowed because the framework I/flutter (30505): builds parent widgets before children, which means a dirty descendant will always be built. I/flutter (30505): Otherwise, the framework might not visit this widget during this build phase. I/flutter (30505): The widget on which setState() or markNeedsBuild() was called was: I/flutter (30505):
Scaffold-[LabeledGlobalKey#5bdc5](state: ScaffoldState#61be4(tickers: tracking 2 I/flutter (30505): tickers))
Building, displaying, and customizing the SnackBar To get started building, displaying, and styling your SnackBar, first complete the following steps: Launch Android Studio or another IDE of your choice. Start a new Flutter project. Select Flutter Application and name the project something like “snackbardemo”
If you need to build a widget dependent on the result of a Stream, you can utilize the StreamBuilder widget. You can make a Stream and pass it as the stream contention. Then, at that point, you need to pass an AsyncWidgetBuilder work that is utilized to construct a widget dependent on the snapshots of the Stream.
To use StreamBuilder , you need to call the constructor below. Basically, you need to create a Stream and pass it as the stream argument. Then, you have to pass an AsyncWidgetBuilder which can be used to build the widget based on the snapshots of the Stream .
First, you must ensure that you are always returning a widget
and then you can schedule the SnackBar for the end of the frame
if(state is AuthUnauthenticated){
  WidgetsBinding.instance.addPostFrameCallback((_) => _showErrorMessage(state.errorMessage));
  return Container();
}
You should also check if the data is null o the snapshot has data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With