ShowDialog from an asynchronus function called in initState Flutter - flutter

I am writing a code to check if the user have the correct version of my app installed otherwise redirect him on the Playstore to update the app.
I am using firebase_remote_config to store a variable to keep tract of the minimum version I want the users to use.
Package_info to get information about users app.
url_launcher to redirect to playstore from the app
My problem is that my method to check the version is asynchronous and it needs to show the dialog to the user before entering the first screen of the app.
I execute it in initState. But the build method builds the first screen before the end of my asynchronous function and my ShowDialog did not render.
How can I firstly show the result of my asynchronous function before the first build?
here is my code after some updates but not showing the Dialog before Navigating to another screen
class Splashscreen extends StatefulWidget {
#override
_SplashscreenState createState() => _SplashscreenState();
}
class _SplashscreenState extends State<Splashscreen> {
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
versionCheck(context);
});
}
Future versionCheck(context) async {
//Get Current installed version of app
final PackageInfo info = await PackageInfo.fromPlatform();
double currentVersion =
double.parse(info.version.trim().replaceAll(".", ""));
//Get Latest version info from firebase config
final RemoteConfig remoteConfig = await RemoteConfig.instance;
try {
// Using default duration to force fetching from remote server.
await remoteConfig.fetch(expiration: const Duration(seconds: 10));
await remoteConfig.activateFetched();
remoteConfig.getString('force_update_current_version');
double nVersion = double.parse(remoteConfig
.getString('force_update_current_version')
.trim()
.replaceAll(".", ""));
if(nVersion > currentVersion){
showDialog(
context: context,
builder: (_) => new AlertDialog(
title: new Text("You are not up to date"),
content: new Text("To use the application, you must update it"),
actions: <Widget>[
FlatButton(
child: Text('Go To Store'),
onPressed: () {
_launchURL(PLAY_STORE_URL);
},
)
],
)
);
}
} on FetchThrottledException catch (exception) {
print(exception);
} catch (exception) {
print(
'Unable to fetch remote config. Cached or default values will be used');
}
}
_launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
#override
Widget build(BuildContext context) {
return ScopedModelDescendant<UserModel>(builder: (context, child, model) {
return new SplashScreen(
seconds: 4,
navigateAfterSeconds:
model.isSignedIn ? HomePage() : SuggestLoginPage(),
image: new Image.asset('assets/images/logo.png', fit: BoxFit.cover,),
backgroundColor: Color(0xff131921),
styleTextUnderTheLoader: new TextStyle( ),
photoSize: 100.0,
loaderColor: Colors.white
);
});
}
}

Create a splash screen when the app running first time show your logo or a loader.
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
cclass _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
checkVersion();
});
}
Future checkVersion({String payload}) async {
var upToDate = false;
if (upToDate)
print('Navigate to Home');
else
return showDialog(
context: context,
builder: (_) => new AlertDialog(
title: new Text("You are not up to date"),
content: new Text("To use the application, you must update it"),
actions: <Widget>[
FlatButton(
child: Text('Go To Store'),
onPressed: () {
//navigate to store
},
)
],
)
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Stackowerflow",
style: TextStyle(
fontFamily: "Josefin",
fontSize: 55,
fontWeight: FontWeight.bold,
color: Colors.grey,
),
),
Image.asset('assets/images/splash.gif',width: 500,
height: 500,),
],
),
),
);
}
Don't forget to run this splash screen into main.dart
Now you can add your function into checkVersion and if up to date then return home or whatever u want to redirect but if it is not then redirect to the store

Related

dart - Flutter FutureBuilder called everytime PageView swap pages causing laggy performances

my FutureBuilder methods return my app everytimes I swap pages.
It cause very bad performances when i navigate between pages.
I have checked solutions on post already in this forum, tried to use provider (didn't fixed my problem), I also tried to move my FutureBuilder into my initState so it's called only one time but didn't manage to make it.
For more details, I printed a line when firebase initialization from FutureBuilder is done, and I witness that everytime i swap pages it print my lane again
My main.dart file:
NotificationService notificationService = NotificationService();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
notificationService.init();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(AppWrapper());
}
class AppWrapper extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _AppWrapperState();
}
}
class _AppWrapperState extends State<AppWrapper> {
#override
Widget build(BuildContext context) {
return OverlaySupport.global(
child: MaterialApp(
theme: ThemeData(
textTheme: GoogleFonts.openSansTextTheme(
Theme.of(context).textTheme,
)),
debugShowCheckedModeBanner: false,
home: App()),
);
}
}
/// We are using a StatefulWidget such that we only create the [Future] once,
/// no matter how many times our widget rebuild.
/// If we used a [StatelessWidget], in the event where [App] is rebuilt, that
/// would re-initialize FlutterFire and make our application re-enter loading state,
/// which is undesired.
class App extends StatefulWidget {
// Create the initialization Future outside of `build`:
#override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
/// The future is part of the state of our widget. We should not call `initializeApp`
/// directly inside [build].
bool? _isLoggedIn;
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
#override
void initState() {
// initIsLoggedIn();
super.initState();
_asyncMethod();
}
void _asyncMethod() async {
try {
// Get values from storage
final storage = new FlutterSecureStorage();
String isLoggedIn = await storage.read(key: "isLoggedIn") ?? "";
if (isLoggedIn == "true") {
//If the user seems logged in, we check it by trying to authenticate
String mail = await storage.read(key: "mail") ?? "";
String password = await storage.read(key: "password") ?? "";
UserResponse userResponse = await APIUser().login(mail, password);
User? user = userResponse.user;
if (user != null) {
setState(() {
_isLoggedIn = true;
});
} else {
//If we cannot connect the user with the stored mail and password, then we redirect the user to the login page
setState(() {
_isLoggedIn = false;
});
print("returning to login page");
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => LoginPage()),
);
}
} else {
//If we cannot connect the user with the stored mail and password, then we redirect the user to the login page
setState(() {
_isLoggedIn = false;
});
print("returning to login page");
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => LoginPage()),
);
}
} catch (e) {
//print the error and redirect the user to the login page
print(e);
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => LoginPage()));
}
}
//The following variables are used to handle the navigation between the 3 main pages
List<Widget> pages = [
SettingsPage(key: PageStorageKey('settings')),
HomePage(key: PageStorageKey('home')),
AccountPage(
key: PageStorageKey('account'),
),
];
int _selectedIndex = 1;
// void _changePage(int index) {
// setState(() {
// _selectedIndex = index;
// });
// }
#override
Widget build(BuildContext context) {
return FutureBuilder(
// Initialize FlutterFire:
future: _initialization,
builder: (context, snapshot) {
// Check for errors
if (snapshot.hasError) {
return somethingWentWrongWidget();
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done &&
_isLoggedIn != null) {
print("Initialize FireBase done");
return appContentWidget();
}
// Otherwise, show something whilst waiting for initialization to complete
print("loadingpage showing to let initialization load");
return LoadingPage();
},
);
}
Widget somethingWentWrongWidget() {
return Center(
child: Text('Someting went wrong', textDirection: TextDirection.ltr),
);
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
PageController _pageController = PageController(
initialPage: 1,
);
final _bottomNavigationItems = [
BottomNavigationBarItem(
activeIcon: ImageIcon(
AssetImage("assets/settingsActive.png"),
size: 32,
),
icon: ImageIcon(
AssetImage("assets/settings.png"),
size: 32,
color: Colors.black,
),
label: ''),
BottomNavigationBarItem(
activeIcon: ImageIcon(
AssetImage("assets/dashboardActive.png"),
size: 32,
),
icon: ImageIcon(
AssetImage("assets/dashboard.png"),
size: 32,
color: Colors.black,
),
label: ''),
BottomNavigationBarItem(
activeIcon: ImageIcon(
AssetImage("assets/userActive.png"),
size: 32,
color: Colors.black,
),
icon: ImageIcon(
AssetImage("assets/user.png"),
size: 32,
color: Colors.black,
),
label: ''),
];
Widget appContentWidget() {
double bottomNavbarHeight = 70;
if (Platform.isIOS) {
bottomNavbarHeight = 90;
}
// check if the user is logged in, if not go to login page
bool loggedIn = _isLoggedIn ?? false;
if (!loggedIn) {
return LoginPage();
} else {
return WillPopScope(
onWillPop: () {
return Future.value(false);
},
child: Scaffold(
key: _scaffoldKey,
body: PageView(
physics: AlwaysScrollableScrollPhysics(),
onPageChanged: (int index) {
setState(() {
_selectedIndex = index;
});
},
controller: _pageController,
pageSnapping: true,
children: [
SettingsPage(key: PageStorageKey('settings')),
HomePage(key: PageStorageKey('home')),
AccountPage(
key: PageStorageKey('account'),
),
],
),
bottomNavigationBar: Container(
height: bottomNavbarHeight,
decoration: BoxDecoration(
boxShadow: [BoxShadow(color: Colors.grey.shade200)]),
child: Theme(
data: ThemeData(
brightness: Brightness.light,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
elevation: 20,
backgroundColor: Colors.white,
selectedFontSize: 0,
//As the label is obligatory, we give it a size of zero
unselectedFontSize: 0,
//As the label is obligatory, we give it a size of zero
items: _bottomNavigationItems,
selectedItemColor: Colors.black,
currentIndex: _selectedIndex,
onTap: (int index) {
_pageController.animateToPage(index,
duration: Duration(milliseconds: 500),
curve: Curves.easeInCubic);
},
),
),
),
),
);
}
}
}
What i would like to achieve is that FutureBuilder initialize only on initState.
you're using await Firebase.initializeApp() already in your main function, why would you need to initialize it one more time in the FutureBuilder ?
On a more general note, your FutureBuilder function is called many times because of the setState on your nav bar, which recalls the build function where your FutureBuilder is.
Whenever you face that, I suggest you split your widget, by having:
-a StatelessWidget containing your FutureBuilder
-a StatefulWidget containing all the display and logic needed.

stop closing showDialogue itself after 15 seconds

I am trying to display an information dialog when starting an application. After closing, another window appears asking for permission. I call it all in the initState function. It works, but I noticed that this first info dialog also closes on its own when 15 seconds have elapsed. How do I fix this? So that while the dialog is not closed by the user, the application will not be loaded further?
class _MyAppState extends State<MyApp> {
final keyIsFirstLoaded = 'is_first_loaded';
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final context = MyApp.navKey.currentState.overlay.context;
await showDialogIfFirstLoaded(context);
await initPlatformState();
});
}
showDialogIfFirstLoaded(BuildContext context, prefs) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool(keyIsFirstLoaded);
if (isFirstLoaded == null) {
return showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return new AlertDialog(
// title: new Text("title"),
content: new Text("//"),
actions: <Widget>[
new FlatButton(
child: new Text(".."),
onPressed: () {
Navigator.of(context).pop();
prefs.setBool(keyIsFirstLoaded, false);
},
),
],
);
},
);
}
}
initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
print('Initialization done');
final _isRunning = await BackgroundLocator.isRegisterLocationUpdate();
setState(() {
isRunning = _isRunning;
});
onStart();
print('Running ${isRunning.toString()}');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
navigatorKey:MyApp.navKey,
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
debugShowCheckedModeBanner: false,
title: '',
theme: ThemeData(),
home: new SplashScreen(),}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
Timer _timer;
bool _visible = true;
startTime() async {
_timer = Timer(new Duration(seconds: 5), navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/home');
}
#override
void initState() {
_timer = Timer(Duration(seconds: 4),
() => setState(
() {
_visible = !_visible;
},
),
);
startTime();
super.initState();
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Image.asset('images/bg.jpg',
fit: BoxFit.cover,
height: 1200,
),
),
Container(
width: double.infinity,
height: 1200,
color: Color.fromRGBO(0, 0, 0, 0.8),
),
Container(
alignment: Alignment.center,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Text(''),
),
),
],
),
),
],
);
}
}
This code displays an Alert dialogue if the user is new and after the button click, it will direct him to another dialogue.
I have tested the code and it doesn't close after 15 seconds. I'm still not sure what you're trying to accomplish but I hope this helps.
Init State
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await dialog1(context);
//await initPlatformState();
});
super.initState();
}
Alert Dialog 1
dialog1(BuildContext context)async{
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isFirstLoaded = prefs.getBool("keyIsFirstLoaded")??true;
if (isFirstLoaded) {
showDialog(
barrierDismissible: false, //disables user from dismissing the dialog by clicking out of the dialog
context: context, builder: (ctx) {
return AlertDialog(
title: Text("dialog 1"), content: Text("Content"), actions: [
TextButton(
child: new Text(".."),
onPressed: () async{
Navigator.pop(ctx);
await dialog2(context);
prefs.setBool("keyIsFirstLoaded", false);
},
),],);
},);
}else{
//not first time
}
}
Alert Dialog 2
void dialog2(BuildContext context)async{
print("dialog 2");
showDialog(context: context, builder: (context) {
return AlertDialog(title: Text("Dialog 2"),content: Text("permissions"),actions: [
TextButton(
child: new Text("close"),
onPressed: () async{
Navigator.pop(context);
//await dialog1(context); //uncomment if you want to go back to dialoge 1
},
),],);
},);
}
You can return a value from Navigator in the first dialog
Navigator.of(context).pop(true);
prefs.setBool(keyIsFirstLoaded, false);
Once it receive true, then only call the second method.
var value = await showDialogIfFirstLoaded(context);
if(value == true) {
await initPlatformState();
}

About ChangeNotifier Provider

I am managing state using provider but ChangeNotifierProvider does not change the value of variable.
I want to show progress indicator when user is registering. But ChangeNotifierProvider does not provide me update value rather it always return me _isLoading = false;
My Code:
AuthServices.dart
class AuthServices with ChangeNotifier {
bool _isLoading = false;
bool get loading => _isLoading;
///Register User
Future registerUser(
{#required String email, #required String password}) async {
try {
_isLoading = true;
notifyListeners();
await http.post(
BackEndConfigs.baseUrl +
BackEndConfigs.version +
BackEndConfigs.auth +
EndPoints.register,
body: {
"email": email,
"password": password
}).then((http.Response response) {
_isLoading = false;
notifyListeners();
return RegisterUser.fromJson(json.decode(response.body));
});
} catch (e) {
print(e);
}
}
}
RegisterScreen.dart
class RegisterScreen extends StatefulWidget {
#override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
AuthServices _authServices = AuthServices();
ProgressDialog pr;
#override
Widget build(BuildContext context) {
pr = ProgressDialog(context, isDismissible: true);
// print(status.loading);
return Scaffold(
appBar:
customAppBar(context, title: 'Register Yourself', onPressed: () {}),
body: _getUI(context),
);
}
Widget _getUI(BuildContext context) {
return LoadingOverlay(
isLoading: false,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
VerticalSpace(10.0),
GreyBoldText('Account Information'),
VerticalSpace(20.0),
IconsButtonRow([
Icon(
FontAwesomeIcons.linkedinIn,
color: Color(0xff0e76a8),
),
Icon(
FontAwesomeIcons.facebook,
color: Color(0xff3b5998),
),
Icon(
FontAwesomeIcons.google,
color: Color(0xff4285F4),
),
]),
VerticalSpace(10.0),
GreyNormalText('or sign up with Email'),
VerticalSpace(10.0),
BlackBoldText("Email"),
AppTextField(
label: 'Email',
),
BlackBoldText("Password"),
AppTextField(
label: 'Password',
),
BlackBoldText("Confirm Password"),
AppTextField(
label: 'Confirm Password',
),
VerticalSpace(20.0),
ChangeNotifierProvider(
create: (_) => AuthServices(),
child: Consumer(
builder: (context, AuthServices user, _) {
return Text(user.loading.toString());
},
),
),
AppButton(
buttonText: 'Next',
onPressed: () async {
// await pr.show();
_registerNewUser();
}),
VerticalSpace(30.0),
ToggleView(ToggleViewStatus.SignUpScreen),
VerticalSpace(20.0),
],
),
),
),
);
}
_registerNewUser() async {
_authServices.registerUser(
email: 'sdjfkldsdf#ssdfdsddfdgsffd.com', password: 'sldjsdfkls');
}
}
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
scaffoldBackgroundColor: Colors.white,
hintColor: FrontEndConfigs.hintColor,
cursorColor: FrontEndConfigs.hintColor,
fontFamily: 'Gilory'),
home: RegisterScreen(),
);
}
}
You created two different instances of AuthServices.
One at the start of your State class and one using the ChangeNotifierProvider.
When calling _registerNewUser you use the AuthServices created in your state class not the provided one.
When you call registerUser on the first AuthServices, the value does not change for the second AuthServices provided by the ChangeNotifierProvider down in the Widget tree.
Try deleting the AuthServices instance created by the state class and move your ChangeNotifierProvider up the widget tree so all your functions share the same instance of AuthServices.

How to remove Alert Dialogs in Flutter

I have create a Alert Dialog for OTP Verification after verifying OTP I close it and then I had created a another dialog which is for data processing... and then I close it.
Result:-
First OTP Dialog closed after OTP verification by calling Navigator.of(context).pop(); and then second dialog just pops up but It does not closed after calling Navigator.of(context).pop();
What I want to do:
Close OTP Dialog after verifying OTP (Works)
Open Progress dialog (Works)
Close it after uploading profile in firebase storage (Does not Works)
Please help me solve this issue.
Thanks in Advance !
You probably forgetting await somewhere in your code.
Try this,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _otpCtrl = TextEditingController();
void dispose() {
_otpCtrl.dispose();
super.dispose();
}
Future<void> _verifyOTP() async {
final String otp = await _inputOtp();
String otpValidationError;
if (otp != null) otpValidationError = await _sendOtpVerifyRequest();
print(otpValidationError);
}
Future<String> _sendOtpVerifyRequest() async {
showDialog(
context: context,
builder: (context) {
return Center(child: CircularProgressIndicator());
},
);
await Future.delayed(Duration(seconds: 2)); //TODO: Do post request here
Navigator.pop(context);
return null;
}
Future<String> _inputOtp() async {
final flag = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Enter OTP"),
content: TextField(
controller: _otpCtrl,
decoration: InputDecoration(
hintText: "x x x x x x",
),
),
actions: <Widget>[
FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.pop(context, false);
},
),
FlatButton(
child: Text("Confirm"),
onPressed: () {
Navigator.pop(context, true);
},
),
],
);
},
);
if (flag == true)
return _otpCtrl.text;
else
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: _verifyOTP,
child: Text("Click Here"),
),
),
);
}
}

How to get shared preferences data before widget build?

I have a few textfields with hint text and bottom navigation. Text entered into the textfield (in Page 1) will be saved to shared preferences "on changed".
When I click on the bottom navigation next page (Page 2) and back to Page 1 again, it seems like the widget rebuild and will show the hintText before shared preference stored data display on the widget.
I have tried to get the sharedpreference data during initState but it does not work. I have also tried to use future builder however when I typed the value in the TextField is not that smooth, sometimes the text would flicker between the characters before and after. I am not sure which method should I use or whether is my my coding wrong.
Could someone advise which method should I use?
Thanks in advance!
login.dart
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: Text('Login Page'),
),
body: bottomNav[currentBottomNavIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTapped,
currentIndex: currentBottomNavIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("Page1"),
),
BottomNavigationBarItem(
icon: Icon(Icons.mail),
title: Text('Page2'),
),
],
),
);
}
page1.dart
class Page1 extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _Page1State();
}
}
class _Page1State extends State<Page1> {
TextEditingController name = TextEditingController();
String name_str;
Future<String> getName(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
name_str = prefs.getString(key);
setState(() {
name = new TextEditingController(text: name_str);
});
return name_str;
}
Future<bool> setName(String key, String value) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.setString(key, value);
}
#override
void initState() {
super.initState();
getName('name');
}
#override
Widget build(BuildContext context) {
//return FutureBuilder(
//future: getName('name'),
//builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
// if (snapshot.hasData) {
return Container(
margin: EdgeInsets.all(100.0),
width: 185,
child: Center(
child: TextField(
controller: name,
textAlign: TextAlign.center,
decoration: new InputDecoration(
hintText: "Name (Original)",
),
onTap:() {
name.clear();
setName('name', '');
},
onChanged: (String str) {
setState(() {
name_str = str;
setName('name', str);
});
},
)
)
);
// }else{
// return Container();
// }
// }
//);
}
}
Page2.dart
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text('Page2'),
),
);
}
}
I think the problem resides here
setState(() {
name = new TextEditingController(text: name_str);
});
doing this
new TextEditingController(text: name_str);
will create a new instance instead just update the value of name controller using shared preferences.
setState(() {
name.text=name_str;
});
This should work for you