flutter - 为什么从共享偏好中获取数据会有延迟?
问题描述
我有一个屏幕来显示来自共享首选项的数据。我已经成功保存并从共享首选项中获取数据。然后我在一个屏幕上有这样的流程:
- 如果用户单击该屏幕,它将检查来自共享首选项的数据。
- 如果数据不为空/不为空,它将显示数据登录,如用户配置文件等。
- 如果数据为空/空,它将显示一个按钮登录。
我得到了该流程的逻辑,但问题是,在屏幕上显示数据(数字 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;
}
....
}
解决方案
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()));
},
),
);
}
}
推荐阅读
- python - 如何在 python 中获取 unicode 换行符?
- bootstrap-4 - Webpack Encore 在单独导出中构建主题?
- database - SQL *Loader 并发程序中如何上传数字类型数据?
- react-native - 如何在本机反应中根据用户选择使用多语言键盘
- r - 传入变量名时,循环遍历 group_by
- amazon-web-services - 有多少百分比的 Amazon DocumentDB RAM 用于索引,多少百分比用于数据?
- passwords - 将用户名和密码传递给 sqlcmd,
- arduino - 是否可以将带有 Ethernet Shield 的 Arduino 连接到带有本地 Blynk 服务器的 Raspberry Pi 并使用该服务器?
- python - 使用没有交叉验证的 LTSM 进行时间序列预测
- sql-server - 'dotnet' 未被识别为 cmdlet、函数、脚本文件或可运行程序的名称