【问题标题】:Why get data from shared preferences have a delayed?为什么从共享偏好中获取数据会有延迟?
【发布时间】:2019-08-14 17:08:45
【问题描述】:

我有一个屏幕来显示来自共享偏好的数据。我已经成功保存并从共享首选项中获取数据。然后我在一个屏幕上有这样的流程:

  1. 如果用户单击该屏幕,它将检查共享首选项中的数据。
  2. 如果数据不为空/不为空,则会显示用户资料等登录数据。
  3. 如果数据为空/空,则会显示按钮登录。

我了解了该流程的逻辑,但问题是,在屏幕上显示数据(数字 2)之前,它首先显示按钮登录几毫秒,然后显示数据。为什么会这样?它没有来自 API / Internet 的数据,我没有使用 FutureBuilder,我只是使用共享首选项。如何杀死这个延迟?以下是我的完整代码:

class MorePage extends StatefulWidget {
  @override
  _MorePageState createState() => _MorePageState();
}

class _MorePageState extends State<MorePage> {

  bool isLoading = false;
  SessionManager _sessionManager = SessionManager();
  int status;

  @override
  void initState() {
    super.initState();
    _sessionManager.getStatusLogin().then((value) { //i use this for get status code login success
      setState(() {
        status = value;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: color_grey_bg,
      body: SafeArea(
        child: getMorePage(),
      ),
    );
  }

  Widget getMorePage() {
    return ListView(
      physics: ClampingScrollPhysics(),
      children: <Widget>[
        Container(
          padding: EdgeInsets.only(
            left: MediaQuery.of(context).size.width / 20,
          ),
          height: MediaQuery.of(context).size.width / 4,
          width: MediaQuery.of(context).size.width,
          color: color_white,
          child: setProfile(),
        ),
      ],
    );
  }

  Widget setProfile() {
    if (status == 200) { // i use this logic to show widget with status login, but it's have delayed like show data from API. How to kill it? Because I using SharedPreferences, not hit the API
      return profileUser();
    } else {
      return notSignIn();
    }
  }

  Widget profileUser() {
    return Row(
      children: <Widget>[
        Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              name,
              style: TextStyle(
                color: color_grey_text,
                fontSize: MediaQuery.of(context).size.width / 26,
                fontWeight: FontWeight.bold,
              ),
            ),
            Text(
              email,
              style: TextStyle(
                color: color_grey_text,
                fontSize: MediaQuery.of(context).size.width / 30,
                fontWeight: FontWeight.normal,
              ),
            ),
            Text(
              role,
              style: TextStyle(
                color: color_grey_text,
                fontSize: MediaQuery.of(context).size.width / 35,
                fontWeight: FontWeight.normal,
              ),
            ),
          ],
        ),
        Spacer(),
        IconButton(
          icon: Icon(
            Icons.arrow_forward_ios,
            size: MediaQuery.of(context).size.height / 40,
          ),
          onPressed: () {
            Navigator.push(context, MaterialPageRoute(builder: (context) => DetailUserPage()));
          },
        ),
      ],
    );
  }

  Widget notSignIn() {
    return Padding(
      padding:
          EdgeInsets.only(left: 50.0, right: 50.0, top: 30.0, bottom: 30.0),
      child: RaisedGradientButton(
        child: Text(
          'Login',
          style: TextStyle(
              color: color_white,
              fontSize: MediaQuery.of(context).size.width / 25),
        ),
        gradient: LinearGradient(
          colors: <Color>[color_blue, color_green],
        ),
        onPressed: () {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => LoginPage()));
        },
      ),
    );
  }
}

这是用于创建 shared_preferences 功能的 SessionManager 类:

class SessionManager {

  .....

  getStatusLogin() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    int status = preferences.getInt("status");
    return status;
  }

  ....

}

【问题讨论】:

    标签: flutter sharedpreferences


    【解决方案1】:

    getprofile函数其实是一个future,你用了async await关键字。 确实,从 sharedpref 中检索数据并不需要时间,但获取 sharedpref 的实例是原因的根源。所以你必须选择解决这个解决方案。

    1-在主函数中获取共享首选项的实例。您可以获取共享首选项的实例并将其作为参数传递给整个应用程序。

    例子

    void main ()async{
        final instance = await sharedPreference.getInstance();
        runApp(MyApp(instance));}
    

    现在在您的 MorePage 小部件中

        class _MorePageState extends State<MorePage> {
      LoginStatus _loginStatus = LoginStatus.notSignIn;
      SessionManager _sessionManager = SessionManager();
      String name, email, role;
      //no need for the async keyword
      getProfile()  { //this func just for show the data
    
        name = widget.preferences.getString("fullname");
        email = widget.preferences.getString("email");
        role = widget.preferences.getString("role");
      }
    
      @override
      void initState() {
        super.initState();
        getProfile();
        _sessionManager.getLoginStatus().then((value) {  //this code for get the status of login
          setState(() {
            _loginStatus = value;
          });
        });
      }
    

    现在 getProfile 函数不是异步的,这意味着在开始时没有毫秒会产生奇怪的行为。

    2-使另一个枚举值'忙' (更简单的解决方案)。只需您可以保留代码原样,但添加一个新的枚举值,该值正忙于向用户提示应用程序正在检查他之前是否登录过,您只需在设置配置文件功能中给他该提示,您'将创建另一个条件if ( _loginStatus == LoginStatus.busy ) return Text('checking user Info')

    希望有帮助!

    编辑: 你这个包get_it 来创建会话管理器类的单例实例,你可以在任何地方访问它。

    GetIt locator = GetIt();
    
    void setUpLocator() {
      locator.registerLazySingleton(() => SessionManager());
    }
    
    void main() async {
      setUpLocator();
      await locator.get<SessionManager>().getStatusLogin();
      runApp(MyApp());
    }
    
    class MorePage extends StatefulWidget {
      @override
      _MorePageState createState() => _MorePageState();
    }
    
    class _MorePageState extends State<MorePage> {
      bool isLoading = false;
      final _sessionManager = locator.get<SessionManager>();
      int status;
    
      @override
      void initState() {
        super.initState();
          //make  property of statuesif you don't have property of the statues 
            //in the session manager class
    
        status = _sessionManager.statues;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: color_grey_bg,
          body: SafeArea(
            child: getMorePage(),
          ),
        );
      }
    
      Widget getMorePage() {
        return ListView(
          physics: ClampingScrollPhysics(),
          children: <Widget>[
            Container(
              padding: EdgeInsets.only(
                left: MediaQuery.of(context).size.width / 20,
              ),
              height: MediaQuery.of(context).size.width / 4,
              width: MediaQuery.of(context).size.width,
              color: color_white,
              child: setProfile(),
            ),
          ],
        );
      }
    
      Widget setProfile() {
        if (status == 200) {
          // i use this logic to show widget with status login, but it's have delayed like show data from API. How to kill it? Because I using SharedPreferences, not hit the API
          return profileUser();
        } else {
          return notSignIn();
        }
      }
    
      Widget profileUser() {
        return Row(
          children: <Widget>[
            Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  name,
                  style: TextStyle(
                    color: color_grey_text,
                    fontSize: MediaQuery.of(context).size.width / 26,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  email,
                  style: TextStyle(
                    color: color_grey_text,
                    fontSize: MediaQuery.of(context).size.width / 30,
                    fontWeight: FontWeight.normal,
                  ),
                ),
                Text(
                  role,
                  style: TextStyle(
                    color: color_grey_text,
                    fontSize: MediaQuery.of(context).size.width / 35,
                    fontWeight: FontWeight.normal,
                  ),
                ),
              ],
            ),
            Spacer(),
            IconButton(
              icon: Icon(
                Icons.arrow_forward_ios,
                size: MediaQuery.of(context).size.height / 40,
              ),
              onPressed: () {
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => DetailUserPage()));
              },
            ),
          ],
        );
      }
    
      Widget notSignIn() {
        return Padding(
          padding:
              EdgeInsets.only(left: 50.0, right: 50.0, top: 30.0, bottom: 30.0),
          child: RaisedGradientButton(
            child: Text(
              'Login',
              style: TextStyle(
                  color: color_white,
                  fontSize: MediaQuery.of(context).size.width / 25),
            ),
            gradient: LinearGradient(
              colors: <Color>[color_blue, color_green],
            ),
            onPressed: () {
              Navigator.push(
                  context, MaterialPageRoute(builder: (context) => LoginPage()));
            },
          ),
        );
      }
    }
    

    【讨论】:

    • 1号的解法,很难。因为在 main() 之后到类 MorePage 太远了。然后对于解决方案 2 仍然有延迟。但我想从 shared_preferences 调用数据没有延迟。因为不是从 API 调用数据,也没有隐藏这个延迟并显示进度/循环。先生还有其他解决方案吗?
    • 顺便说一句,对不起,我忘了附上我在 SessionManager 类中创建并在 initState() 中调用的 getLoginStatus() 的代码。我已经更新了我的帖子
    • 解决方案一中,可以使用继承的widget或者provider来访问实例。
    • 在解决方案 2 中,我说延迟不会消失,但您可以处理这几毫秒来显示加载文本。
    • 有没有关于使用继承小部件访问 SharedPreferences 变量的参考资料?我已经使用循环处理了这几毫秒,但我认为最好杀死/删除然后使用显示一些小部件来处理。
    【解决方案2】:

    我认为一旦从共享首选项中获取值就显示 Circle Progress 然后显示主容器。

    请检查以下代码:-

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: color_grey_bg,
          body: SafeArea(
            child: LoginStatus.notSignIn ? const CircularProgressIndicator(
                            valueColor: AlwaysStoppedAnimation<Color>(
                                        Color(colorPrimary))),
                        ) : getMorePage()
          ),
        );
      }
    

    【讨论】:

    • 这不是解决方案。因为我需要从使用共享首选项获取数据中删除延迟/终止延迟。未隐藏此延迟并显示进度。
    【解决方案3】:

    我认为你应该创建一个类,然后使用引用-:

    Future<void> main() async{
     ShareP.preferences = await SharedPreferences.getInstance();  
    }
    
    class ShareP {
     static SharedPreferences preferences;
    }
    

    现在您可以引用它(“ShareP.preferences”)并获取您的 SharedPreference 值

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-04
      • 2016-12-31
      • 1970-01-01
      相关资源
      最近更新 更多