Flutter устанавливает стартовую страницу на основе общих предпочтений

#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);
    }
  }
}