#dart #flutter
#dart #flutter
Вопрос:
Я безуспешно пытался загрузить разные страницы в соответствии с моими общими настройками предпочтений.
Основываясь на нескольких сообщениях, найденных в stackoverflow, я в конечном итоге получаю следующее решение:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:testing/screens/login.dart';
import 'package:testing/screens/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget page = Login();
Future getSharedPrefs() async {
String user = Preferences.local.getString('user');
if (user != null) {
print(user);
this.page = Home();
}
}
@override
void initState() {
super.initState();
this.getSharedPrefs();
}
@override
Widget build(BuildContext context) {
return MaterialApp(home: this.page);
}
}
class Preferences {
static SharedPreferences local;
/// Initializes the Shared Preferences and sets the info towards a global variable
static Future init() async {
local = await SharedPreferences.getInstance();
}
}
Переменная user
не равна null, потому что print(user)
возвращает ожидаемое значение, но login
экран всегда открывается.
Ответ №1:
Ваша проблема в том, что ваш метод сборки возвращается до завершения вашего getSharedPrefs future. getSharedPrefs возвращается мгновенно, как только оно вызывается, потому что оно асинхронное, и вы рассматриваете его как «Запустить и забыть», не ожидая. Видя, что вы не можете ожидать в своей функции initState, это имеет смысл.
Именно здесь вы хотите использовать виджет FutureBuilder. Создайте Future, который возвращает логическое значение (или перечисление, если вам нужно больше состояний), и используйте future builder в качестве домашнего дочернего элемента, чтобы вернуть правильный виджет.
Создайте свое будущее
Future<bool> showLoginPage() async {
var sharedPreferences = await SharedPreferences.getInstance();
// sharedPreferences.setString('user', 'hasuser');
String user = sharedPreferences.getString('user');
return user == null;
}
Когда user равен null, это вернет true. Используйте это будущее в сборщике будущего, чтобы отслеживать изменения значений и реагировать соответствующим образом.
@override
Widget build(BuildContext context) {
return MaterialApp(home: FutureBuilder<bool>(
future: showLoginPage(),
builder: (buildContext, snapshot) {
if(snapshot.hasData) {
if(snapshot.data){
// Return your login here
return Container(color: Colors.blue);
}
// Return your home here
return Container(color: Colors.red);
} else {
// Return loading screen while reading preferences
return Center(child: CircularProgressIndicator());
}
},
));
}
Я запустил этот код, и он отлично работает. Вы должны увидеть синий экран, когда требуется войти в систему, и красный экран, когда присутствует пользователь. Раскомментируйте строку в showLoginPage для тестирования.
Ответ №2:
Существует гораздо более приятный способ сделать это. Предполагая, что у вас есть несколько маршрутов и логический ключ SharedPreference, который называется инициализированным. Вам необходимо использовать функцию WidgetsFlutterBinding.ensureInitialized() перед вызовом метода runApp().
void main() async {
var mapp;
var routes = <String, WidgetBuilder>{
'/initialize': (BuildContext context) => Initialize(),
'/register': (BuildContext context) => Register(),
'/home': (BuildContext context) => Home(),
};
print("Initializing.");
WidgetsFlutterBinding.ensureInitialized();
await SharedPreferencesClass.restore("initialized").then((value) {
if (value) {
mapp = MaterialApp(
debugShowCheckedModeBanner: false,
title: 'AppName',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routes,
home: Home(),
);
} else {
mapp = MaterialApp(
debugShowCheckedModeBanner: false,
title: 'AppName',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routes,
home: Initialize(),
);
}
});
print("Done.");
runApp(mapp);
}
Код класса SharedPreference :
class SharedPreferencesClass {
static Future restore(String key) async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
return (sharedPrefs.get(key) ?? false);
}
static save(String key, dynamic value) async {
final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
if (value is bool) {
sharedPrefs.setBool(key, value);
} else if (value is String) {
sharedPrefs.setString(key, value);
} else if (value is int) {
sharedPrefs.setInt(key, value);
} else if (value is double) {
sharedPrefs.setDouble(key, value);
} else if (value is List<String>) {
sharedPrefs.setStringList(key, value);
}
}
}