#flutter #flutter-test
#flutter #flutter-тест
Вопрос:
Недавно я разрабатываю первое в истории приложение в Flutter, и я знаю только основы. Итак, вот проблема, с которой я сталкиваюсь в настоящее время.
Мне нужно перейти на один из двух экранов, либо зарегистрироваться, либо на домашнюю страницу в зависимости от старого / нового пользователя, поэтому то, что я сделал, здесь.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Register.dart';
import 'HomePage.dart';
class Authenticate extends StatefulWidget {
@override
_AuthenticateState createState() => _AuthenticateState();
}
class _AuthenticateState extends State<Authenticate> {
String _userName = "";
@override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? "";
});
}
Widget build(BuildContext context) {
if (_userName == "") {
print('name : $_userName , NEW user'); // ERROR - why it's printing on console for old User ?
return Register();
} else {
return HomePage(_userName);
}
}
}
Итак, проблема в том, что даже если я открываю приложение через старого пользователя, оно печатает отладочный код, написанный для нового пользователя, и видимость экрана регистрации составляет около 0,3 секунды.
Итак, что я должен сделать, чтобы исправить это?
Ответ №1:
Печать происходит из-за этой строки кода:
SharedPreferences pref = await SharedPreferences.getInstance();
является асинхронным, что означает, что он может быть вызван в какой-то более поздний момент времени. Из-за этого build
сначала вызывается метод, затем ваш _getUserName
метод завершен, что вызывает a setState
и build
снова вызывает метод.
Возможно, вы захотите показать какой-то экран загрузчика, пока не будет инициализирован sharedPrefernces, а затем решить, показывать Register
или Home
нет. страница.
Пример кода:
class _AuthenticateState extends State<Authenticate> {
String _userName = "";
bool _isLoading = true;
@override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? "";
_isLoading = false;
});
}
Widget build(BuildContext context) {
if (_isLoading) {
return Center(child: CupertinoActivityIndicator());
} else if (_userName == "") {
print('name : $_userName , NEW user'); // ERROR - why it's printing on console for old User ?
return Register();
} else {
return HomePage(_userName);
}
}
}
Ответ №2:
Попробуйте это:
class _AuthenticateState extends State<Authenticate> {
String _userName;
@override
void initState() {
super.initState();
_getUserName();
}
_getUserName() async {
SharedPreferences pref = await SharedPreferences.getInstance();
setState(() {
_userName = pref.getString('userName') ?? '';
});
}
Widget build(BuildContext context) {
if (_userName == null) {
return Center(child: CircularProgressIndicator());
} else if (_userName == '') {
print('name : $_userName , NEW user');
return Register();
} else {
return HomePage(_userName);
}
}
}
В этом случае _userName
null
изначально и будет присвоено значение только после _getUserName()
возврата либо пустой строки, либо старого имени пользователя. Когда значение равно null, виджет вместо этого создаст индикатор выполнения. Если вы этого не хотите, просто верните a Container()
.
Комментарии:
1. Большое вам спасибо, на самом деле я впервые использую await и sync, поэтому не имел ни малейшего представления. Теперь я чувствую себя глупо. Собираюсь изучить его полностью 🙂
2. youtu.be/SmTCmDMi4BY — это действительно классное видео по этому вопросу