Как правильно перейти к одному из двух экранов для пользователей в Flutter?

#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 — это действительно классное видео по этому вопросу