Flutter - My BlocBuilder is not notified of the state change

60 Views Asked by At

My

My BlocBuilder is not notified of the state change but I do have MenuAnimationError which is emitted. My output :

Instance of 'MenuAnimationInitial'
INITIAL
[-in]
MenuAnimationError instantiated
[in-]

My main file.

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pmu/features/players/menu_animation_cubit.dart';
import 'package:pmu/features/players/player_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MultiBlocProvider(
        providers: [
          // BlocProvider(create: (context) => PlayerCubit()),
          BlocProvider<MenuAnimationCubit>(create: (_) => MenuAnimationCubit()),
        ],
        child: PlayerPage(),
      ),
    );
  }
}

My widget where are BlocBuilder. player_page.dart

// features/players/player_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pmu/features/players/menu_animation_cubit.dart';

class PlayerPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Player Page'),
      ),
      body: 
          BlocBuilder<MenuAnimationCubit, MenuAnimationState>(
            builder: (context, state) {
              final menuAnimationCubit = context.read<MenuAnimationCubit>();
              print(state);
              if (state is MenuAnimationLoaded) {
                print("LOADED");
              } else if (state is MenuAnimationInitial) {
                print("INITIAL");
                menuAnimationCubit.loadMenuAnimation();
                return Container(
                  color: Colors.yellow,
                  width: double.infinity, // Takes up the full width
                  height: double.infinity, // Takes up the full height
                );
              } else if (state is MenuAnimationError) {
                return Container(
                  color: Colors.red,
                  width: double.infinity, // Takes up the full width
                  height: double.infinity, // Takes up the full height
                );
              } else {
                return Container(
                  color: Colors.blue,
                  width: double.infinity, // Takes up the full width
                  height: double.infinity, // Takes up the full height
                );
              }
            },
          ),
    );
  }
  
}

My state

features/players/menu_animation_state.dart

// features/players/menu_animation_state.dart

part of 'menu_animation_cubit.dart';

abstract class MenuAnimationState {
  const MenuAnimationState();
}

class MenuAnimationInitial extends MenuAnimationState {
  const MenuAnimationInitial();
}

class MenuAnimationLoading extends MenuAnimationState {}

class MenuAnimationLoaded extends MenuAnimationState {
  final VideoPlayerController videoController;

  const MenuAnimationLoaded(this.videoController);
}

class MenuAnimationError extends MenuAnimationState {
  final String error;

  const MenuAnimationError(this.error);

  // Add a named constructor for debugging purposes
  MenuAnimationError.debug(this.error) {
    print('MenuAnimationError instantiated');
  }
}

My cubit features/players/menu_animation_cubit.dart

// features/players/menu_animation_cubit.dart

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:bloc/bloc.dart';

part 'menu_animation_state.dart';

class MenuAnimationCubit extends Cubit<MenuAnimationState> {
  MenuAnimationCubit() : super(const MenuAnimationInitial());

  void loadMenuAnimation() {
    print("[-in]");
    emit(MenuAnimationError.debug("Error loading video"));
    print("[in-]");
  }
  
}

My loadMenuAnimation() function is called, my MenuAnimationError class is instantiated, but my BlocBuilder is not notified of the state change...

1

There are 1 best solutions below

0
On

You can use scheduleMicrotask or postFrameCallback instead of directly changing state during build.

} else if (state is MenuAnimationInitial) {
  print("INITIAL");
  scheduleMicrotask(() {
    menuAnimationCubit.loadMenuAnimation();
  });

Most likely you will do some async operation on this method, then it won't be needed.

  void loadMenuAnimation() async {
    print("[-in]");
    await Future.delayed(const Duration(seconds: 2)); //your future code here
    emit(MenuAnimationError.debug("Error loading video"));
    print("[in-] ${state}");
  }