Bloc: Bloc login example, LoginBloc is giving null inside the BlocBuilder

Created on 24 Feb 2019  Β·  18Comments  Β·  Source: felangel/bloc

Describe the bug
LoginBloc is giving null inside the BlocBuilder from the Bloc Login Example

Expected behavior
I expected to open the loginForm.

Screenshots
If applicable, add screenshots to help explain your problem.

*Logs *
I/flutter ( 3542): ══║ EXCEPTION CAUGHT BY WIDGETS LIBRARY β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
I/flutter ( 3542): The following assertion was thrown building LoginForm(dirty, state: _LoginFormState#bace3):
I/flutter ( 3542): 'package:flutter_bloc/src/bloc_builder.dart': Failed assertion: line 22 pos 16: 'bloc != null': is
I/flutter ( 3542): not true.
I/flutter ( 3542):
I/flutter ( 3542): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 3542): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 3542): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 3542): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 3542):
I/flutter ( 3542): When the exception was thrown, this was the stack:
I/flutter ( 3542): #2 new BlocBuilder
package:flutter_bloc/src/bloc_builder.dart:22
I/flutter ( 3542): #3 _LoginFormState.build
package:concierge_app/…/widgets/login_form.dart:30
I/flutter ( 3542): #4 StatefulElement.build
package:flutter/…/widgets/framework.dart:3809
I/flutter ( 3542): #5 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3721
I/flutter ( 3542): #6 Element.rebuild
package:flutter/…/widgets/framework.dart:3547
I/flutter ( 3542): #7 ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3701
I/flutter ( 3542): #8 StatefulElement._firstBuild
package:flutter/…/widgets/framework.dart:3848
I/flutter ( 3542): #9 ComponentElement.mount
package:flutter/…/widgets/framework.dart:3696
I/flutter ( 3542): #10 Element.inflateWidget
package:flutter/…/widgets/framework.dart:2950
I/flutter ( 3542): #11 Element.updateChild
package:flutter/…/widgets/framework.dart:2753
I/flutter ( 3542): #12 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3732
I/flutter ( 3542): #13 Element.rebuild
package:flutter/…/widgets/framework.dart:3547
I/flutter ( 3542): #14 ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3701
I/flutter ( 3542): #15 ComponentElement.mount
package:flutter/…/widgets/framework.dart:3696
I/flutter ( 3542): #16 Element.inflateWidget
package:flutter/…/widgets/framework.dart:2950
I/flutter ( 3542): #17 Element.updateChild
package:flutter/…/widgets/framework.dart:2753
I/flutter ( 3542): #18 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3732
I/flutter ( 3542): #19 Element.rebuild
package:flutter/…/widgets/framework.dart:3547
I/flutter ( 3542): #20 ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:3701
I/flutter ( 3542): #21 ComponentElement.mount
package:flutter/…/widgets/framework.dart:3696
I/flutter ( 3542): #22 ParentDataElement.mount
package:flutter/…/widgets/framework.dart:4047


login_form.dart

import 'package:flutter/material.dart';

import 'package:flutter_bloc/flutter_bloc.dart';

import '../blocs/auth_bloc/authentification.dart';
import '../blocs/login_bloc/login.dart';

class LoginForm extends StatefulWidget {
final LoginBloc loginBloc;
final AuthenticationBloc authenticationBloc;

LoginForm({
Key key,
@required this.loginBloc,
@required this.authenticationBloc,
}) : super(key: key);

@override
State createState() => _LoginFormState();
}

class _LoginFormState extends State {
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();

LoginBloc get _loginBloc => widget.loginBloc;

@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _loginBloc,
builder: (
BuildContext context,
LoginState state,
) {
if (state is LoginFailure) {
_onWidgetDidBuild(() {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('${state.error}'),
backgroundColor: Colors.red,
),
);
});
}

    return Form(
      child: Column(
        children: [
          TextFormField(
            decoration: InputDecoration(labelText: 'username'),
            controller: _usernameController,
          ),
          TextFormField(
            decoration: InputDecoration(labelText: 'password'),
            controller: _passwordController,
            obscureText: true,
          ),
          RaisedButton(
            onPressed:
                state is! LoginLoading ? _onLoginButtonPressed : null,
            child: Text('Login'),
          ),
          Container(
            child:
                state is LoginLoading ? CircularProgressIndicator() : null,
          ),
        ],
      ),
    );
  },
);

}

void _onWidgetDidBuild(Function callback) {
WidgetsBinding.instance.addPostFrameCallback((_) {
callback();
});
}

void _onLoginButtonPressed() {
_loginBloc.dispatch(LoginButtonPressed(
username: _usernameController.text,
password: _passwordController.text,
));
}
}


login_bloc.dart

import 'dart:async';

import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import '../../services/loginRepository.dart';

import '../auth_bloc/authentification.dart';
import './login.dart';

class LoginBloc extends Bloc {
final LoginRepository loginRepository;
final AuthenticationBloc authenticationBloc;

LoginBloc({
@required this.loginRepository,
@required this.authenticationBloc,
}) : assert(loginRepository != null),
assert(authenticationBloc != null);

@override
LoginState get initialState => LoginInitial();

@override
Stream mapEventToState(
LoginState currentState,
LoginEvent event,
) async* {
if (event is LoginButtonPressed) {
yield LoginLoading();

  try {
    final token = await loginRepository.authenticate(
      username: event.username,
      password: event.password,
    );

    authenticationBloc.dispatch(LoggedIn(token: token));
    yield LoginInitial();
  } catch (error) {
    yield LoginFailure(error: error.toString());
  }
}

}
}

question

Most helpful comment

@felangel thanks for your Help. I was using flutter_bloc: ^0.18.3.
After updating it to v0.20.0 my issue is resolved.

All 18 comments

Can you please share the code for how LoginBloc gets passed to LoginForm? I’m guessing it’s not being injected correctly. Please include login_page.dart as well as main.dart

solved

It was not injected correctly in build function located in login_page.dart

Thank's

solved

It was not injected correctly in build function located in login_page.dart

Thank's

@MarcioQuimbundo Can you elaborate on how you did the right injection please? I am having a similar issue where bloc becomes null after the first mapEventToState

@aytunch are you able to share your code? I can take a look and try to help πŸ˜„

@felangel i will post the project soon in a new issue

@felangel @aytunch i am using login example "https://github.com/felangel/bloc/tree/master/examples/flutter_firebase_login"
Not did any modification , I am getting same issue. Please can you explian what's wrong with it...
Failed assertion: line 44 pos 16: 'bloc != null': is not true.

@zubyf09 the examples are using flutter_bloc v0.20.0 which does not require a bloc in BlocBuilder or BlocListener. Can you please make sure you’re using v0.20.0?

@felangel thanks for your Help. I was using flutter_bloc: ^0.18.3.
After updating it to v0.20.0 my issue is resolved.

@felangel Can you elaborate on how you did the right injection please? I am facing a similar issue with the context, it always is returnder as dirty.

@JCFlores93 can you provide a sample app which reproduces the issue?

void main() async {
FlutterError.onError = (FlutterErrorDetails details) {
if (isInDebugMode) {
FlutterError.dumpErrorToConsole(details);
} else {
Zone.current.handleUncaughtError(details.exception, details.stack);
}
};
WidgetsFlutterBinding.ensureInitialized();
await FlutterCrashlytics().initialize();

runZoned>(() async {
runApp(MultiBlocProvider(
providers: [
BlocProvider(
builder: (context) => PostsBloc(),
),
BlocProvider(
builder: (context) => CurrentUserBloc(),
)
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: _buildTheme(),
initialRoute: '/',
routes: {
'/': (context) => MenuContainer(),
},
),
));
}, onError: (error, stackTrace) async {
await FlutterCrashlytics()
.reportCrash(error, stackTrace, forceCrash: false);
});
}

@felangel The first provider works fine, but the second it's not working. I think it could be a problem of DI. Because the first bloc is called in the MenuContainer and the second bloc is other widget.

`class MenuContainer extends StatefulWidget {
MenuContainer();
@override
_MenuState createState() => new _MenuState();
}

class _MenuState extends State {
PostsBloc _postsBloc;

@override
void initState() {
super.initState();
_postsBloc = BlocProvider.of(context);
_postsBloc.dispatch(LoadPosts());
}
_MenuState();
int _selectedIndex = 0;

List createTabOptions({List posts}) {
return [
QueriesAnimalContainer(posts: posts, refresh: _refresh),
SearchContainer(posts: posts, refresh: _refresh),
PostScreenContainer(),
LoginContainer(),
];
}
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _postsBloc,
builder: (BuildContext context, PostState state) {
if (state is PostsLoading) {
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PostsLoaded) {
final widgetOptions = createTabOptions(posts: state.posts);
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
bottomNavigationBar: BottomNavigatorBar(
selectedIndex: _selectedIndex, onItemTapped: _onItemTapped),
body: SafeArea(
child:
Center(child: widgetOptions.elementAt(_selectedIndex))),
);
}
return Container(height: .0, width: .0);
});
}
`

@JCFlores93 when you use MultiBlocProvider you need to explicitly provide the types for each BlocProvider like:

MultiBlocProvider(
  providers: [
    BlocProvider< PostsBloc>(
      builder: (context) => PostsBloc(),
    ),
    BlocProvider<CurrentUserBloc>(
      builder: (context) => CurrentUserBloc(),
    ),
  ],
  child: ...

Also when you're looking up the bloc via BlocProvider you also need to specify the type:

_postsBloc = BlocProvider.of<PostsBloc>(context);

Hope that helps πŸ‘

@felangel where the context is dirty is in LoginContainer.

@JCFlores93 when you use MultiBlocProvider you need to explicitly provide the types for each BlocProvider like:

MultiBlocProvider(
  providers: [
    BlocProvider< PostsBloc>(
      builder: (context) => PostsBloc(),
    ),
    BlocProvider<CurrentUserBloc>(
      builder: (context) => CurrentUserBloc(),
    ),
  ],
  child: ...

Also when you're looking up the bloc via BlocProvider you also need to specify the type:

_postsBloc = BlocProvider.of<PostsBloc>(context);

Hope that helps

Yes. I did it.

@felangel I having issues when I look for the second one in LoginContainer. The state always arrives null, but the CurrentUserState contains props, but in LoginContainer is always null

@override
Widget build(BuildContext context) {
_currentUserBloc = BlocProvider.of(context);
return BlocBuilder(
bloc: _currentUserBloc,
builder: ( context, CurrentUserState state) {
....
}

@JCFlores93 as I mentioned, you need to specify the type when doing a lookup using BlocProvider.

You can't just use BlocProvider.of(context) because there's no way for the bloc library to know which bloc you want.

You have to specify the type like:

BlocProvider.of<CurrentUserBloc>(context);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

felangel picture felangel  Β·  35Comments

realtebo picture realtebo  Β·  41Comments

sawankumarbundelkhandi picture sawankumarbundelkhandi  Β·  108Comments

mariaszek9003 picture mariaszek9003  Β·  29Comments

anderscheow picture anderscheow  Β·  75Comments