Flutter Bloc - Flutter Bloc state not updating

Viewed 448

i'm just getting started with flutter bloc. i try to make state but it always goes to initial. what's the solution?

BLOC

class VisiMisiBloc extends Bloc<VisiMisiEvent, VisiMisiState> {
  VisiMisiBloc(this.visiMisiRepository) : super(VisiMisiInitial());

  final VisiMisiRepository visiMisiRepository;
  
  @override
  Stream<VisiMisiState> mapEventToState(VisiMisiEvent event) async* {
    if (event is GetVisiMisiList) {
      yield* _getVisiMisi(event, state);
    }
  }

  Stream<VisiMisiState> _getVisiMisi(VisiMisiEvent event, VisiMisiState state) async* {
    yield VisiMisiLoading();
    try {
      ResponseModel<VisiMisiModel> response = await visiMisiRepository.getVisiMisi();
      print(response);

      if (response.statusCode == 0) {
        int insertedId = await visiMisiRepository.insertVisiMisi(response.data);
        print(insertedId);
        List<VisiMisiModel> visiMisiList = await visiMisiRepository.getAllVisiMisi();
        yield VisiMisiLoaded(visiMisiList);

      } else {
        yield VisiMisiError(response.errorMessage);
      }
    } on Exception catch (e) {
      yield VisiMisiError(e.toString());
    }
  }
}

STATE

part of 'visi_misi_bloc.dart';

abstract class VisiMisiState extends Equatable {
  const VisiMisiState();
}

class VisiMisiInitial extends VisiMisiState {
  const VisiMisiInitial();
  @override
  List<Object>get props => [];
}


class VisiMisiLoading extends VisiMisiState {
  const VisiMisiLoading();
  @override
  List<Object>get props => [];
}

class VisiMisiLoaded extends VisiMisiState {
  final List<VisiMisiModel> visiMisiModel;
  const VisiMisiLoaded(this.visiMisiModel);
  @override
  List<Object> get props => [visiMisiModel];
}

class VisiMisiError extends VisiMisiState {
  final String message;
  const VisiMisiError(this.message);
  @override
  List<Object>get props => [message];
}

EVENT

part of 'visi_misi_bloc.dart';

abstract class VisiMisiEvent extends Equatable{
  const VisiMisiEvent();
}

class GetVisiMisiList extends VisiMisiEvent {
  @override
  List<Object> get props => [];
}

REPOSITORY

abstract class VisiMisiRepository {
  Future<int> insertVisiMisi(VisiMisiModel todo);
  Future<ResponseModel<VisiMisiModel>> getVisiMisi();
  Future<List<VisiMisiModel>> getAllVisiMisi();
}

REPOSITORY IMPL

class VisiMisiRepositoryImpl extends VisiMisiRepository {
  final NetworkInfoImpl networkInfo;
  final RemoteDataSource remoteDatasource;
  final VisiMisiDao dao;

  VisiMisiRepositoryImpl(this.networkInfo, this.remoteDatasource, this.dao);

  @override
  Future<ResponseModel<VisiMisiModel>> getVisiMisi() {
    return remoteDatasource.visiMisi();
  }

  @override
  Future<int> insertVisiMisi(VisiMisiModel todo) {
    return dao.upsert(todo);
  }

  @override
  Future<List<VisiMisiModel>> getAllVisiMisi() {
    return dao.getAll(userTABLE, VisiMisiModel.fromJson);
  }
}

REMOTE DATASOURCE

Future<ResponseModel<VisiMisiModel>> visiMisi() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String auth_token = prefs.getString("auth_token");
    try {
      final response = await httpClient.get(ServiceUrl.visiMisi, auth_token);

      if(response.statusCode != 200){
        throw new Exception('Error getting visi misi');
      }

      return ResponseModel<VisiMisiModel>.fromJson(response, VisiMisiModel.fromJson);
    }catch(e){
      print(e);
    }
  }

VIEW

class VisiMisiPage extends StatefulWidget {
  @override
  _VisiMisiPageState createState() => _VisiMisiPageState();
}

class _VisiMisiPageState extends State<VisiMisiPage> {
  VisiMisiRepository repository;

  @override
  void initState(){
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          backgroundColor: AppColor.white,
          appBar: AppBar(
            title: Text("VISI & MISI", style: TextStyle(fontSize: 16, color: AppColor.deepCerulean),),
            backgroundColor: Colors.white,
            elevation: 0,
            automaticallyImplyLeading: false,
            brightness: Brightness.light,
            leading: IconButton(
              icon: new Icon(Icons.arrow_back, color: AppColor.deepCerulean,),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ),
          body: BlocProvider<VisiMisiBloc>(
            create: (_) => VisiMisiBloc(repository),
            child: BlocBuilder<VisiMisiBloc, VisiMisiState>(
                  builder: (context, state) {
                    if (state is VisiMisiInitial) {
                      //BlocProvider.of<VisiMisiBloc>(context).add(GetVisiMisiList());
                      return Center(child: Text(state.toString()),);
                    } else if (state is VisiMisiLoading) {
                      return Center(child: CircularProgressIndicator(),);
                    } else if (state is VisiMisiLoaded) {
                      return SingleChildScrollView(
                        child: Container(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              _visiWidget(context, state),
                              SizedBox(height: 20,),
                              _misiWidget(context),
                              SizedBox(height: 30,),
                              _footerWidget(context)
                            ],
                          ),
                        ),
                      );
                    } else if (state is VisiMisiError) {
                      return Center(child: Text(state.message),);
                    }
                  }
              )
            ),
          )
    );
  }

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

I get an Unhandled Exception: Unhandled error NoSuchMethodError: The method 'getVisiMisi' was called on null.

in view, the state shows in VisiMisiInitial, and doesn't want to update to VisiMisiLoading

3 Answers

try to initialize the repository like so:

class _VisiMisiPageState extends State<VisiMisiPage> {
  VisiMisiRepository repository;

  @override
  void initState(){
    super.initState();
    repository = VisiMisiRepositoryImpl( parameters here ); // add this one
  }

To initialize repository, you should use RepositoryProvider.

For example, something like that

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiRepositoryProvider(
        providers: [
          RepositoryProvider<UserRepository>(
            create: (context) => UserRepository(),
          ),
        ],
        child: MultiBlocProvider(
            providers: [
              BlocProvider<LoginBloc>(
                create: (context) => LoginBloc(context.read<UserRepository>()),
              ),
            ],
            child: Widget()));
  }
}

Then, it will be automatically initialized

I have analysed your code ,and I found 2 mistakes:

1st. you just created instance of your VisiMisiRepository and not initialised. and you are calling their methods that's why you getting error Unhandled error NoSuchMethodError: The method 'getVisiMisi' was called on null.

2nd. You just initialised your bloc within passing instance of repository, and haven't performed any bloc event . that's why code keep showing initial state.

You might have got your answer. if not, take help from here it'll surely help you:

replace this:

create: (_) => VisiMisiBloc(repository),

with this:

create: (_) => VisiMisiBloc(VisiMisiRepository())..add(GetVisiMisiList()),

In your widget tree:

body: BlocProvider<VisiMisiBloc>(
            create: (_) => VisiMisiBloc(VisiMisiRepository())..add(GetVisiMisiList()), //initialising bloc within repository and hit event as well.
           
            child: BlocBuilder<VisiMisiBloc, VisiMisiState>(
                  builder: (context, state) {
                    if (state is VisiMisiInitial) {
                  
                      return Center(child: Text(state.toString()),);
                    } else if (state is VisiMisiError) {
                      return Center(child: Text(state.message),);
                    } else if (state is VisiMisiLoaded) {
                      return SingleChildScrollView(
                        child:  Container(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              _visiWidget(context, state),
                              SizedBox(height: 20,),
                              _misiWidget(context),
                              SizedBox(height: 30,),
                              _footerWidget(context)
                            ],
                          ),
                        ),
                      );
                    } 

                    return  Center(child: CircularProgressIndicator(),);
                  }
              )
            ),

this answer will also resolve Unhandled error NoSuchMethodError: The method 'getVisiMisi' was called on null error.

Related