首页 > 解决方案 > 为什么从共享偏好中获取数据会有延迟?

问题描述

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

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

  ....

}

标签: fluttersharedpreferences

解决方案


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()));
        },
      ),
    );
  }
}

推荐阅读