Невозможно сохранить значение переменной класса в flutter / dart при использовании Future

#flutter #dart

#flutter #dart

Вопрос:

Я хочу сохранить значение предпочтения общего доступа в переменной класса, но оно вообще не работает, значение не сохраняется в переменной. вот мой код, в основном я хочу сохранить в переменную _uid , но когда я обращаюсь к ней в своем пользовательском интерфейсе, она печатает «»..

 import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class User with ChangeNotifier {
  FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
  Firestore _firestore = Firestore.instance;
  bool _loggedIn = false;
  bool get loggedIn => _loggedIn;
  String _uid = "";
  String get uid => _uid;
  User() {
    getPrefState().then((val) {
      // do some operation
      _uid = val.toString() ?? "test";
    });
    
    //init();
  }
  Future init() async {
    //var data;
    //_uid = getPrefState();
    /*SharedPreferences.getInstance().then((value) => {
          _uid = value.getString("uid") ?? "d",
          data = "dsdasd",
        });*/
    /*try {
      SharedPreferences prefs = await SharedPreferences.getInstance();

      _uid = data;
    } catch (err) {
      //pass.
    }*/

    //var uid = prefs.getString("uid") ?? "d";
    /*if (uid != null) {
      _loggedIn = true;
    }*/
    //_uid = "dsd";
    //notifyListeners();
  }

  Future<String> getPrefState() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    //Return String
    String stringValue = prefs.getString('uid') ?? "test";
    return stringValue;
  }

  Future<void> saveId(uid) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString("uid", uid);
  }

  Future<void> saveUserInDocument(String uid, String name, String sap) {
    _firestore.collection("users").document(uid).setData({
      "name": name,
      "sap": sap,
      'role': "student",
    });
  }

  Future<FirebaseUser> getCurrentUser() async {
    return await _firebaseAuth.currentUser();
  }

  // user signup.
  Future<void> signup(
      String email, String password, String name, String sap) async {
    FirebaseUser user = (await _firebaseAuth.createUserWithEmailAndPassword(
            email: email, password: password))
        .user;
    if (user != null) {
      saveUserInDocument(user.uid, name, sap);
      saveId(user.uid);
      _loggedIn = true;
      notifyListeners();
    }
  }

  /// user login
  Future<void> login(String email, String password) async {
    FirebaseUser user = (await _firebaseAuth.signInWithEmailAndPassword(
            email: email, password: password))
        .user;
    //if (user != null) {
    saveId(user.uid);
    _loggedIn = true;
    notifyListeners();
    //}
  }

  /// User logout
  Future<void> logout() async {
    _firebaseAuth.signOut();
    saveId(null);
    _loggedIn = false;
    notifyListeners();
  }

  /// reset user password
  Future<void> resetPassword(String email) async {
    await _firebaseAuth.sendPasswordResetEmail(email: email);
  }
}
  

Вот мой класс пользовательского интерфейса, в котором я хочу его использовать
user.uid

 import "package:flutter/material.dart";
import 'package:riphahwebresources/data/User.dart';
import 'package:riphahwebresources/pages/auth/login_ui.dart';
import 'package:shared_preferences/shared_preferences.dart';

class WebResourceAppDrawer extends StatefulWidget {
  @override
  _WebResourceAppDrawerState createState() => _WebResourceAppDrawerState();
}

class _WebResourceAppDrawerState extends State<WebResourceAppDrawer> {
  User user = User();

  @override
  Widget build(BuildContext context) {
    List<Widget> children = [];
    children.add(
      ListTile(
        leading: Icon(Icons.home),
        title: Text("Home"),
      ),
    );
    if (user.loggedIn) {
      children.add(ListTile(
        leading: Icon(Icons.people),
        title: Text("Profile"),
        onTap: () => {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => LoginUi()))
        },
      ));
      children.add(ListTile(
        leading: Icon(Icons.people),
        title: Text("Logout"),
        onTap: () => {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => LoginUi()))
        },
      ));
    } else {
      children.add(ListTile(
        leading: Icon(Icons.people),
        title: Text(user.uid),
        onTap: () => {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => LoginUi()))
        },
      ));
    }
    return Drawer(
      child: ListView(
        padding: const EdgeInsets.all(8),
        children: <Widget>[
          DrawerHeader(
            child: Text("Menu"),
          ),
          ...children,
        ],
      ),
    );
  }
}
  

Вы можете видеть из метода init , я пробую разные вещи, но idk у меня ничего не работает.
Большое вам спасибо.

Ответ №1:

При использовании ChangeNotifier вам необходимо вызвать notifyListeners , чтобы распространить изменение на ваш класс пользовательского интерфейса:

notifyListeners() . Вызывайте этот метод каждый раз, когда модель изменяется таким образом, что может изменить пользовательский интерфейс вашего приложения.

Документы Flutter по управлению состоянием

В качестве напоминания вам понадобятся следующие 3 вещи, чтобы заставить управление состоянием работать:

  1. Настройте класс, который extends ChangeNotifier (который вы сделали, но просто замените with на extends )

  2. Добавьте a ChangeNotifierProvider над виджетом, где вам требуется значение (т. Е. Над вашим WebResourceAppDrawer виджетом пользовательского интерфейса)

  3. Теперь получите доступ User , обернув виджет пользовательского интерфейса с Consumer<User>

Вот как будет выглядеть полный минимальный пример:

 import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
          body: Center(
              child:
                  ChangeNotifierProvider(create: (_) => User(), child: UI()))),
                  // 'UI' can now access the newly created User() since it's a
                  // child of ChangeNotifierProvider
    );
  }
}

class UI extends StatefulWidget {
  @override
  _UIState createState() => _UIState();
}

class _UIState extends State<UI> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Consumer<User>(
          builder: (context, user, child) => Text("User ${user.uid}")),
          // This is how user can be accessed within UI
    );
  }
}

class User extends ChangeNotifier {
  String _uid = "(empty)";
  String get uid => _uid;

  User() {
    getPrefState().then((val) {
      _uid = val;
      notifyListeners(); // this call triggers a rebuild of UI
    });
  }

  getPrefState() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getString('uid');
  }
}