简体   繁体   English

为什么我的可观察变量无法使用 GetX 更新 Flutter 中的“main.dart”?

[英]Why my observable variable can not update the "main.dart" in Flutter using GetX?

The following code is my auth_controller.dart code.以下代码是我的auth_controller.dart代码。 I see the response comes from the backend works and it is what was expected and I have token and the isAuth value changes to true after I submit the form:我看到response来自后端工作,这是预期的,我有token ,并且在我提交表单后isAuth值更改为true

enum AuthMode { Signup, Login }

class AuthController extends GetxController
    with GetSingleTickerProviderStateMixin {
  static AuthController instance = Get.find();
  Rx<dynamic>? authMode = AuthMode.Login.obs;
  RxBool? isLoading = false.obs;
  String? _token;
  DateTime? _expiryDate;
  String? _userId;
  Timer? _authTimer;
  final _isAuth = false.obs;

  AnimationController? controller;
  Animation<Offset>? slideAnimation;
  Animation<double>? opacityAnimation;
  // late TextEditingController passwordController;
  // final key = GlobalKey<FormState>();

  @override
  void onInit() {
    super.onInit();
    controller = AnimationController(
      vsync: this,
      duration: const Duration(
        milliseconds: 300,
      ),
    );
    slideAnimation = Tween<Offset>(
      begin: const Offset(0, -1.5),
      end: const Offset(0, 0),
    ).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.fastOutSlowIn,
      ),
    );
    opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: controller as Animation<double>,
        curve: Curves.easeIn,
      ),
    );
    // _heightAnimation.addListener(() => setState(() {}));

    // passwordController = TextEditingController();
  }

  @override
  void onClose() {
    super.onClose();
    // passwordController.dispose();
  }

  bool get isAuth {
    _isAuth.value = token != null;
    return _isAuth.value;
  }

  String? get token {
    if (_expiryDate != null &&
        _expiryDate!.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    return null;
  }

  String? get userId {
    return _userId;
  }

  Future<void> _authenticate(
      String email, String password, String urlSegment) async {
    // print('app is here!!!5555');

    final host = UniversalPlatform.isAndroid ? '10.0.2.2' : '127.0.0.1';
    final url = Uri.parse('http://$host:8000/api/$urlSegment');
    //final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
    //final url = Uri.parse('http://127.0.0.1:8000/api/$urlSegment');

    try {
      final http.Response response = await http.post(
        url,
        headers: {"Content-Type": "application/json"},
        body: json.encode(
          {
            'email': email,
            'password': password,

            //'returnSecureToken': true,
          },
        ),
      );
      print('this is responsde ');
      print(json.decode(response.body));

      final responseData = json.decode(response.body);

      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      } else {
        _token = responseData['idToken'];
        _userId = responseData['id'];
        _expiryDate = DateTime.now().add(
          Duration(
            seconds: responseData['expiresIn'],
          ),
        );
      }
      _autoLogout();
      // update();
      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode(
        {
          'token': _token,
          'userId': _userId,
          'expiryDate': _expiryDate!.toIso8601String(),
        },
      );
      prefs.setString('userData', userData);

      // print(prefs.getString('userData'));

    } catch (error) {
      throw error;
    }
  }

  Future<void> signup(String email, String password) async {
    return _authenticate(email, password, 'signup');
  }

  Future<void> login(String email, String password) async {
    return _authenticate(email, password, 'login');
  }

  Future<bool> tryAutoLogin() async {
    final prefs = await SharedPreferences.getInstance();
    if (!prefs.containsKey('userData')) {
      return false;
    }
    final Map<String, Object> extractedUserData = Map<String, Object>.from(
        json.decode(prefs.getString('userData') as String));
    final expiryDate =
        DateTime.parse(extractedUserData['expiryDate'] as String);

    if (expiryDate.isBefore(DateTime.now())) {
      return false;
    }
    _token = extractedUserData['token'] as String;
    _userId = extractedUserData['userId'] as String;
    _expiryDate = expiryDate;
    // update();
    _autoLogout();
    return true;
  }

  Future<void> logout() async {
    _token = null;
    _userId = null;
    _expiryDate = null;
    if (_authTimer != null) {
      _authTimer!.cancel();
      _authTimer = null;
    }
    // update();
    final prefs = await SharedPreferences.getInstance();
    // prefs.remove('userData');
    prefs.clear();
  }

  void _autoLogout() {
    if (_authTimer != null) {
      _authTimer!.cancel();
    }
    final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timeToExpiry), logout);
  }
}

But it will still sticks to the Authentication page and won't go to the Home page as I defined in my main.dart file:但它仍然会坚持身份验证页面,并且不会 go 到我在main.dart文件中定义的主页:

void main() {
  Get.put(MenuController());
  Get.put(NavigationController());
  Get.put(AuthController());
  Get.put(AuthCard);
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Obx(() => GetMaterialApp(
          initialRoute: AuthController.instance.isAuth
              ? homeScreenRoute
              : authenticationScreenRoute,
          unknownRoute: GetPage(
              name: '/not-found',
              page: () => PageNotFound(),
              transition: Transition.fadeIn),
          getPages: [
            GetPage(
                name: rootRoute,
                page: () {
                  return SiteLayout();
                }),
            GetPage(
                name: authenticationScreenRoute,
                page: () => const AuthenticationScreen()),
            GetPage(name: homeScreenRoute, page: () => const HomeScreen()),
          ],
          debugShowCheckedModeBanner: false,
          title: 'BasicCode',
          theme: ThemeData(
            scaffoldBackgroundColor: light,
            textTheme: GoogleFonts.mulishTextTheme(Theme.of(context).textTheme)
                .apply(bodyColor: Colors.black),
            pageTransitionsTheme: const PageTransitionsTheme(builders: {
              TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
              TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
            }),
            primarySwatch: Colors.blue,
          ),
        ));
  }
}

What is the problem and how can I fix that?有什么问题,我该如何解决?

Initial route is set only once when the app starts, and based on what you've shown isAuth will always return false by the time GetMaterialApp is built.初始路由仅在应用程序启动时设置一次,并且根据您显示的内容, isAuth将始终在GetMaterialApp构建时返回 false。

Wrapping your whole app in an Obx is not going to trigger a navigation based on what you have set for the initial route.将整个应用程序包装在Obx中不会触发基于您为初始路线设置的导航。 Its way past that by the time you've run any login attempt.当您运行任何登录尝试时,它已经过去了。

You need to manually navigate to home screen after a successful login.成功登录后,您需要手动导航到主屏幕。

Instead I suggest checking for a non null token from storage before the app starts and if its null, go to your auth page and if not, go to your home page. Instead I suggest checking for a non null token from storage before the app starts and if its null, go to your auth page and if not, go to your home page. Neither of which would require an Obx around GetMaterialApp because you need to properly initialize _isAuth and await it before runApp() .两者都不需要Obx周围的GetMaterialApp ,因为您需要正确初始化_isAuth并在runApp()之前await它。

I could simply resolve the problem by adding following lines to my main.dart file:我可以通过在我的main.dart文件中添加以下行来简单地解决问题:

  home: Obx(() => AuthController.instance.isAuth
      ? const HomeScreen()
      : const AuthenticationScreen()),

And removing the followings:并删除以下内容:

   initialRoute
   : AuthController.instance.isAuth
       ? homeScreenRoute
       : authenticationScreenRoute,

I also deleted the Obx before the GetMaterialApp() .我还在GetMaterialApp()之前删除了Obx

The new main.dart looks like this:新的main.dart看起来像这样:

void main() {
  Get.put(MenuController());
  Get.put(NavigationController());
  Get.put(AuthController());
  Get.put(AuthCard);
  AuthController.instance.isAuth ? runApp(MyApp()) : runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      unknownRoute: GetPage(
          name: '/not-found',
          page: () => PageNotFound(),
          transition: Transition.fadeIn),
      getPages: [
        GetPage(
            name: rootRoute,
            page: () {
              return SiteLayout();
            }),
        GetPage(
            name: authenticationScreenRoute,
            page: () => const AuthenticationScreen()),
        GetPage(name: homeScreenRoute, page: () => const HomeScreen()),
      ],
      debugShowCheckedModeBanner: false,
      title: 'BasicCode',
      theme: ThemeData(
        scaffoldBackgroundColor: light,
        textTheme: GoogleFonts.mulishTextTheme(Theme.of(context).textTheme)
            .apply(bodyColor: Colors.black),
        pageTransitionsTheme: const PageTransitionsTheme(builders: {
          TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
          TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
        }),
        primarySwatch: Colors.blue,
      ),
      home: Obx(() => AuthController.instance.isAuth
          ? const HomeScreen()
          : const AuthenticationScreen()),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM