Flutter:使用共享首选项时对 null 的方法调用

Posted

技术标签:

【中文标题】Flutter:使用共享首选项时对 null 的方法调用【英文标题】:Flutter : method call on null when using shared preference 【发布时间】:2021-03-30 15:42:53 【问题描述】:

我想使用共享偏好来保持用户登录,并且我正在使用带有 provider 的 api。 我试图把它放在 main 但我不知道怎么做,因为我有两个不同的页面要走,所以我在第一页使用它,但我发现另一个错误

[错误:flutter/lib/ui/ui_dart_state.cc(177)] 未处理的异常: NoSuchMethodError:在 null 上调用了方法“登录”。 E/颤振 ( 4199):接收者:空

这是我使用的方法

UserProvider userProvider;
  ServiceProvider serviceProvider;
  bool alive = true;
  bool isLoading = false;
  var page;

  @override
  initState() 
    init();
    super.initState();
  

  init() async 
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool language = prefs.getBool('language');
    bool type = prefs.getBool('type');
    bool login = prefs.getBool('islog');
    if (alive) 
      if (language == true && type == true && login == true) 
        signIn();
       else if ((language == true && type == false && login == true)) 
        visitor();
      
     else 
      if (alive) 
        setState(() 
          isLoading = false;
        );
      
    
  

  signIn() async 
    //var res = await userProvider.residentLogin(context, phone, pass);
    SharedPreferences prefs = await SharedPreferences.getInstance();
    var phone = prefs.getString('phone');
    String pass = prefs.getString("pass");
    bool type = prefs.getBool('type');
      print("Shared ***************resident********************************");
      await userProvider.residentLogin(context, phone, pass);
      await serviceProvider.getHomeServiceList(context);
      await serviceProvider.getAdsList(context);
      await serviceProvider.getVideosList(context);
      Navigator.pushReplacement(context,
          MaterialPageRoute(builder: (context) => ResidentBottomTab()));
      print('Hello Tourist !!');
    
  

  visitor() async 
    SharedPreferences prefs = await SharedPreferences.getInstance();
    var phone = prefs.getString('phone');
    String pass = prefs.getString("pass");
    await userProvider.login(context, phone, pass);
    await serviceProvider.getVisitorAdsList(context);
    await serviceProvider.getVisitorVideosList(context);
    bool type = prefs.getBool('type');
    print("Shared ******************visitor*****************************");
    if (alive) 
      Navigator.pushReplacement(
          context, MaterialPageRoute(builder: (context) => VisitorHome()));
      print('Hello Tourist !!');
    
  

  @override
  void dispose() 
    alive = false;
    super.dispose();
  

登录方式

Future<VisitorLoginModel> login(BuildContext context, phone, pass) async 
    final Map<String, dynamic> body = 
      'phone': phone,
      'password': pass,
      'token': '123',
      'serial_number': '123',
      'lang': 'en',
      'os': 'android',
    ;

    _isLoading = true;
    notifyListeners();
    print('Starting request');
    http.Response response = await http.post(Environment.userLogin,
        body: json.encode(body), headers: Environment.requestHeader);
    print('Completed request');
    print('user SignUp response : $response.body');
    //print(body.toString());
    Map<String, dynamic> res = json.decode(response.body);
    var results;
    if (res['status'] == 1) 
      // login successful
      _visitorLoginModel = parseVisitorLogin(response.body);
      Provider.of<LoginVisitorUserProvider>(context, listen: false).userData =
          visitorLoginModel;
      Provider.of<LoginVisitorUserProvider>(context, listen: false)
          .sessionToken = visitorLoginModel.data.token;
      headers = Provider.of<LoginVisitorUserProvider>(context, listen: false)
          .httpHeader;
      // print('token');
      print('this is session token' +
          Provider.of<LoginVisitorUserProvider>(context, listen: false)
              .sessionToken);
     else 
      // login failed;
      results =
          FailedRequest(code: 401, message: res['massage'], status: false);
    
    _isLoading = false;
    notifyListeners();
    return visitorLoginModel;
  

所以任何人都有解决此案的想法!

【问题讨论】:

【参考方案1】:

这里的问题是 userProvider 正在声明但未初始化,serviceProvider 也是如此

在 Flutter 中,任何未初始化的变量都会隐式赋值为 null 因此,在 await userProvider.login(context, phone, pass); 行,您调用 login 方法,其中 userProvider 不仅被初始化

要解决此问题,请执行以下操作, 在 initState 中,

userProvider = Provider.of<UserProvider>(context, listen: false);

【讨论】:

【参考方案2】:

方法调用await userProvider.login(context, phone, pass); 正在一个未初始化的变量上完成。 UserProvider userProvider; 已声明但未初始化

【讨论】:

这是对的,请您提一下如何在 main 中使用它? @MariamYounes 请参考我现在附上的答案。您必须在 initState 中对其进行初始化 我有问题,请检查一下 但仍然不知道如何在 main 上使用共享偏好方法

以上是关于Flutter:使用共享首选项时对 null 的方法调用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:共享首选项的奇怪行为

Flutter:使用共享首选项插件存储保存的收藏列表

如何使用 dart/flutter 中的共享首选项保存和获取列表列表

Flutter 中的共享首选项错误 - Mac 上的 iOS

如何将对象列表中的布尔收藏夹保存到 Flutter 中的共享首选项

Flutter 存储共享首选项中的自定义类列表