For some reason, the Build method is called twice which results in two MainContent widgets being created. The problem is that in one of my widgets a Listener displays messages to the user according to certain actions. Because Maincontent is duplicated, messages are displayed twice.
How to prevent the MainContent widget from being duplicated?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = ProductBlocObserver();
var productStorage = ProductStorage();
await productStorage.products().then((localProducts) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isMember', false);
await prefs.setBool('membershipError', false);
await prefs.setBool('firstOpen', true);
await prefs.setString('memberFirstName', '');
await prefs.setString('token', '');
runApp(App(list: localProducts));
});
}
class App extends StatelessWidget {
List<LocalProductEntity> list;
App({Key? key, required this.list}) : super(key: key) {
list = list;
}
@override
Widget build(BuildContext context) {
return BlocProvider <ListBloc>(
create: (_) => ListBloc(list: list),
child: MaterialApp(
debugShowCheckedModeBanner: true,
title: constants.appTitle,
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch().copyWith(
primary: Color(ColorsLNC.green5),
secondary: Color(ColorsLNC.green1),
),
),
home: BlocPage()
),
);
}
}
class BlocPage extends StatelessWidget {
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
late Future<bool> isMember;
late Future<bool> membershipError;
late Future<bool> firstOpen;
late Future<String> memberFirstName;
late Future<String> token;
late BuildContext context;
BlocPage({super.key});
@override
Widget build(BuildContext context) {
this.context = context;
isMember = _prefs.then((SharedPreferences prefs) {
return prefs.getBool('isMember') ?? false;
});
membershipError = _prefs.then((SharedPreferences prefs) {
return prefs.getBool('membershipError') ?? false;
});
firstOpen = _prefs.then((SharedPreferences prefs) {
return prefs.getBool('firstOpen') ?? false;
});
memberFirstName = _prefs.then((SharedPreferences prefs) {
return prefs.getString('memberFirstName') ?? '';
});
token = _prefs.then((SharedPreferences prefs) {
return prefs.getString('token') ?? '';
});
return FutureBuilder(
future: membershipFlow(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
return snapshot.data;
}
});
}
Future<Widget> membershipFlow() async {
if (await isMember == true && await membershipError == false) {
return SplashPage(
mainContext : context,
goToPage: MainContent(),
text: await memberFirstName,
duration: 2,
);
} else if (await isMember == false && await membershipError == false) {
return const MembershipForm();
} else if (await isMember == false && await membershipError == true) {
return ErrorPage(text: Babel.translate(key: 'E_WRONG_MEMBERSHIP'));
} else {
return ErrorPage(text: Babel.translate(key: 'E_UNEXPECTED'));
}
}
}
Use const
with both constructor and while using it.
For example
const BlocPage({super.key})
and const BlocPage()
.
You code has different issue tough. You could refactor your code like this and build won't be called repeatedly.
class BlocPage extends StatelessWidget {
const BlocPage({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: membershipFlow(context),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
return snapshot.data;
}
});
}
Future<Widget> membershipFlow(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
final isMember = prefs.getBool('isMember') ?? false;
final membershipError = prefs.getBool('membershipError') ?? false;
final firstOpen = prefs.getBool('firstOpen') ?? false;
final memberFirstName = prefs.getString('memberFirstName') ?? '';
final token = prefs.getString('token') ?? '';
if (isMember == true && membershipError == false) {
return SplashPage(
mainContext : context,
goToPage: MainContent(),
text: memberFirstName,
duration: 2,
);
} else if (isMember == false && membershipError == false) {
return const MembershipForm();
} else if (isMember == false && membershipError == true) {
return ErrorPage(text: Babel.translate(key: 'E_WRONG_MEMBERSHIP'));
} else {
return ErrorPage(text: Babel.translate(key: 'E_UNEXPECTED'));
}
}
}