I am learning flutter + bloc and start with a demo. Start of project I create starting app by delay 3 second and next to home page like this:
StartCubit
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'start_state.dart';
class StartCubit extends Cubit<StartState> {
StartCubit() : super(StartInitial());
void startRunning() {
loadData();
}
void loadData() async {
emit(StartDoing(0));
await Future.delayed(Duration(seconds: 1));
emit(StartDoing(1));
await Future.delayed(Duration(seconds: 1));
emit(StartDoing(2));
await Future.delayed(Duration(seconds: 1));
emit(StartDoing(3));
await Future.delayed(Duration(seconds: 1));
emit(StartDone());
}
}
And this is code in start page:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:money_lover/home_page/home_page.dart';
import 'package:money_lover/start/bloc/start_cubit.dart';
class StartPage extends StatelessWidget {
const StartPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => StartCubit(),
child: StartView(),
);
}
}
class StartView extends StatefulWidget {
const StartView({Key? key}) : super(key: key);
@override
State<StartView> createState() => _StartViewState();
}
class _StartViewState extends State<StartView> {
@override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: BlocBuilder<StartCubit, StartState>(
builder: (context, state) {
if (state is StartInitial) {
context.read<StartCubit>().startRunning();
} else if (state is StartDone) {
Future.delayed(Duration.zero, () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
);
});
}
return Text('Starting $state');
},
)));
}
}
If I don't call future delay with zero time It will show error before next screen.
And I don't need print stateDone when go to next screen, have any way to code more correctly ?
I tried add delay addPostFrameCallback in this link Error: Unhandled Exception: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 2845 pos 18: '!navigator._debugLocked': is not true it is ok but I think maybe I code not correctly way.
You should be using a listener
to handle the navigation.
In your case a blocconsumer will do
BlocConsumer exposes a builder and listener in order react to new states.
BlocConsumer<StartCubit,StartState>(
listener: (context, state) {
if (state is StartDone) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
);
}
},
builder: (context, state) {
if (state is StartInitial) {
// Instead of running this here, you can run it in your build if you want init state like behavior.
context.read<StartCubit>().startRunning();
}
return Text('Starting $state');
}
)
Running in build method
class _StartViewState extends State<StartView> {
@override
Widget build(BuildContext context) {
context.read<StartCubit>().startRunning();
return Scaffold(body: Center(child: BlocBuilder<StartCubit, StartState>(