Last active
February 4, 2022 10:59
-
-
Save comatory/c1bd789802312b4d287fee40e0f939de to your computer and use it in GitHub Desktop.
example application showing that emit does not trigger multiple calls to BlocBuilder builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:math' show max; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:equatable/equatable.dart'; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({Key? key}) : super(key: key); | |
// This widget is the root of your application. | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'BLoC', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: BlocProvider<NetworkBloc>( | |
create: (_) => NetworkBloc(), child: const MyHomePage()), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
const MyHomePage({Key? key}) : super(key: key); | |
@override | |
State<MyHomePage> createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
late NetworkBloc _bloc; | |
late StreamSubscription<NetworkState> _streamSubscription; | |
List<String> _logs = []; | |
@override | |
void initState() { | |
_bloc = BlocProvider.of<NetworkBloc>(context); | |
_streamSubscription = _bloc.stream.listen(_handleBlocChange); | |
_logs = [..._logs, _createLog(_bloc.state.status)]; | |
super.initState(); | |
} | |
@override | |
void dispose() { | |
_streamSubscription.cancel(); | |
super.dispose(); | |
} | |
void _handleBlocChange(NetworkState state) { | |
setState(() { | |
_logs = [ | |
..._logs.sublist(max(_logs.length - 6, 0), _logs.length), | |
_createLog(state.status), | |
]; | |
}); | |
} | |
String _createLog(NetworkStatus status) => '${DateTime.now()} $status'; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ | |
TextButton( | |
onPressed: () { | |
BlocProvider.of<NetworkBloc>(context) | |
.add(const NetworkStart()); | |
}, | |
child: const Text('Start')), | |
TextButton( | |
onPressed: () { | |
setState(() { | |
_logs = []; | |
}); | |
}, | |
child: const Text('Clear')), | |
BlocBuilder<NetworkBloc, NetworkState>( | |
buildWhen: (prev, current) => prev.allow != current.allow, | |
builder: (_, state) { | |
return Checkbox( | |
value: state.allow, | |
onChanged: (value) { | |
_bloc.add(NetworkToggleReset(value ?? state.allow)); | |
}); | |
}), | |
]), | |
BlocBuilder<NetworkBloc, NetworkState>(builder: (_, state) { | |
debugPrint(state.status.toString()); | |
return SizedBox( | |
width: 100, | |
height: 100, | |
child: Builder(builder: (_) { | |
switch (state.status) { | |
case NetworkStatus.loading: | |
return const CircularProgressIndicator(); | |
case NetworkStatus.finished: | |
return const Text('Finished'); | |
case NetworkStatus.initial: | |
default: | |
return const Text('Initial'); | |
} | |
}), | |
); | |
}), | |
Expanded( | |
child: ListView.builder( | |
itemCount: _logs.length, | |
itemBuilder: (_, i) => ListTile(title: Text(_logs[i])))), | |
])), | |
); | |
} | |
} | |
class NetworkBloc extends Bloc<NetworkEvent, NetworkState> { | |
NetworkBloc() | |
: super(const NetworkState(status: NetworkStatus.initial, allow: true)) { | |
on<NetworkStart>(_mapNetworkStartEventToState); | |
on<NetworkToggleReset>(_mapNetworkToggleResetEventToState); | |
} | |
Future<void> _mapNetworkStartEventToState( | |
NetworkStart event, | |
Emitter<NetworkState> emit, | |
) async { | |
emit(state.copyWith(status: NetworkStatus.loading)); | |
if (!state.allow) { | |
emit(state.copyWith(status: NetworkStatus.initial)); | |
return; | |
} | |
await Future.delayed(const Duration(seconds: 2)); | |
emit(state.copyWith(status: NetworkStatus.finished)); | |
} | |
Future<void> _mapNetworkToggleResetEventToState( | |
NetworkToggleReset event, | |
Emitter<NetworkState> emit, | |
) async { | |
emit(state.copyWith(allow: event.enabled)); | |
} | |
} | |
abstract class NetworkEvent { | |
const NetworkEvent(); | |
} | |
class NetworkStart extends NetworkEvent { | |
const NetworkStart(); | |
} | |
class NetworkToggleReset extends NetworkEvent { | |
const NetworkToggleReset(this.enabled); | |
final bool enabled; | |
} | |
enum NetworkStatus { | |
initial, | |
loading, | |
finished, | |
} | |
class NetworkState extends Equatable { | |
const NetworkState({ | |
required this.status, | |
required this.allow, | |
}); | |
final NetworkStatus status; | |
final bool allow; | |
NetworkState copyWith({ | |
NetworkStatus? status, | |
bool? allow, | |
}) { | |
return NetworkState( | |
status: status ?? this.status, allow: allow ?? this.allow); | |
} | |
@override | |
get props => [status, allow]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment