Flutter Provider "notifyListener()" 不改变状态
Flutter Provider "notifyListener()" does not change the state
我的 Provider class 中有一个方法 login
,它在我的 HomeScreen()
的 initState()
方法中调用,在 login function
中我基本上 register/check 如果用户信息存储在服务器中,然后我 post 请求服务器获取该用户的信息。一切正常 但是 当我 hot restart
或 reopens
应用程序时,它继续加载,因为显然三元操作不满足但如果我打印数据在 login
函数中,它确实发生了变化,因此 notifyListeners()
无法正常工作,因此状态没有发生变化。 (现在我必须 hot reload
ctrl+s
,然后状态会改变,一切都会成功加载)。
主屏幕():
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<Course> courses = [];
@override
void initState() {
super.initState();
courses = Course().getAllCourses();
Future.delayed(Duration.zero, () async {
Provider.of<LoginProvider>(context, listen: false).login();
});
}
@override
Widget build(BuildContext context) {
bool isLoading =
Provider.of<LoginProvider>(context, listen: false).isLoading;
User user = Provider.of<LoginProvider>(context, listen: false).user;
print("INITIAL: $isLoading");
print("INITIAL: ${user.data!.categoryList!.length}");
return Scaffold(
backgroundColor: Colors.white,
body: !isLoading && user.data != null
? ListView.separated(
itemCount: courses.length,
separatorBuilder: (context, index) {
return Divider();
},
itemBuilder: (context, index) {
final course = courses[index];
final courseNew = user.data!.categoryList![index];
print("INSIDE: $isLoading");
print("INSIDE: ${user.data!.categoryList!.length}");
if (courses.length == user.data!.categoryList!.length) {
return ... // full custom
}
return Center(
child: Text("No Data recieved from backend"),
);
},
)
: Center(
child: CircularProgressIndicator(
strokeWidth: 4,
)),
);
}
}
(courses
和user.data.categoryList
的长度相同)
Provider 文件中的登录函数:
login() async {
await _checkIsUserLoggedIn();
if (_deviceDetails.deviceID == "") {
print("[INFO] NEW USER DEVICE DETECTED");
print("[INFO] LOGGING IN...");
await _getDeviceDetails();
// fetching platform details, if success, carry-on, else throw error
try {
if (_deviceDetails.deviceID != "") {
// post request to server
Map<String, dynamic> requestBody = {
'device_id': _deviceDetails.deviceID
};
http.Response response = await http
.post(Uri.parse(Constants.LOGIN_ENDPOINT), body: requestBody);
_user = userFromJson(response.body);
_deviceDetails.userID = _user.data!.userId!;
_deviceDetails.userName = _user.data!.name!;
_deviceDetails.token = _user.data!.token!;
await _saveLoginDetails(_deviceDetails);
print("[INFO] USER LOGGED IN SUCCESSFULLY");
}
} catch (error) {
print("[INFO] ERROR WHILE FETCHING DEVICE DETAILS: $error");
}
} else {
print("[INFO] THIS USER DEVICE IS ALREADY LOGGED IN");
print("[INFO] FETCHING EXISTING USER DETAILS");
Map<String, dynamic> requestBody = {'device_id': _deviceDetails.deviceID};
http.Response response = await http
.post(Uri.parse(Constants.LOGIN_ENDPOINT), body: requestBody);
_user = userFromJson(response.body);
print("INSIDE LOGIN FUNCTION: ${_user.data!.categoryList!.length}"); // prints 2 in console (correct)
}
_isLoading = false;
notifyListeners();
}
控制台输出:
应用首次加载或热重启时的输出:
I/flutter ( 3495): INITIAL: true
I/flutter ( 3495): INITIAL: 1
I/flutter ( 3495): [INFO] THIS USER DEVICE IS ALREADY LOGGED IN
I/flutter ( 3495): [INFO] FETCHING EXISTING USER DETAILS
I/flutter ( 3495): INSIDE LOGIN FUNCTION: 2
应用程序热重载 (Ctrl+S) 时的输出:
I/flutter ( 3495): INITIAL: false
I/flutter ( 3495): INITIAL: 2
I/flutter ( 3495): INSIDE: false
I/flutter ( 3495): INSIDE: 2
I/flutter ( 3495): INSIDE: false
I/flutter ( 3495): INSIDE: 2
如您所见,热重载后,状态发生了变化,但并非没有,这意味着 notifyListeners()
在 login
函数中的行为不正常?
这里可能有什么问题,我真的很困惑...
非常感谢任何帮助!
Class LogInProvider{
bool _isLogin = false;
setIsLogin(bool isLogin){
_isLogin = isLogin;
notifyListeners();
}
isLogin(){
return _isLogin;
}
}
然后在 ui class .
获取登录信息:
...
child : Consumer<LoginInProvider>(
builder: (context,_loginProvider, child) {
return Text("${_loginProvider.isLogin}");
},
设置登录信息:
Provider.of<LoginInfoProvider>(context).setIslogIn(true);
您需要在等待更新时设置收听true
:
bool isLoading =
Provider.of<LoginProvider>(context, listen: true).isLoading;
User user = Provider.of<LoginProvider>(context, listen: true).user;
我的 Provider class 中有一个方法 login
,它在我的 HomeScreen()
的 initState()
方法中调用,在 login function
中我基本上 register/check 如果用户信息存储在服务器中,然后我 post 请求服务器获取该用户的信息。一切正常 但是 当我 hot restart
或 reopens
应用程序时,它继续加载,因为显然三元操作不满足但如果我打印数据在 login
函数中,它确实发生了变化,因此 notifyListeners()
无法正常工作,因此状态没有发生变化。 (现在我必须 hot reload
ctrl+s
,然后状态会改变,一切都会成功加载)。
主屏幕():
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List<Course> courses = [];
@override
void initState() {
super.initState();
courses = Course().getAllCourses();
Future.delayed(Duration.zero, () async {
Provider.of<LoginProvider>(context, listen: false).login();
});
}
@override
Widget build(BuildContext context) {
bool isLoading =
Provider.of<LoginProvider>(context, listen: false).isLoading;
User user = Provider.of<LoginProvider>(context, listen: false).user;
print("INITIAL: $isLoading");
print("INITIAL: ${user.data!.categoryList!.length}");
return Scaffold(
backgroundColor: Colors.white,
body: !isLoading && user.data != null
? ListView.separated(
itemCount: courses.length,
separatorBuilder: (context, index) {
return Divider();
},
itemBuilder: (context, index) {
final course = courses[index];
final courseNew = user.data!.categoryList![index];
print("INSIDE: $isLoading");
print("INSIDE: ${user.data!.categoryList!.length}");
if (courses.length == user.data!.categoryList!.length) {
return ... // full custom
}
return Center(
child: Text("No Data recieved from backend"),
);
},
)
: Center(
child: CircularProgressIndicator(
strokeWidth: 4,
)),
);
}
}
(courses
和user.data.categoryList
的长度相同)
Provider 文件中的登录函数:
login() async {
await _checkIsUserLoggedIn();
if (_deviceDetails.deviceID == "") {
print("[INFO] NEW USER DEVICE DETECTED");
print("[INFO] LOGGING IN...");
await _getDeviceDetails();
// fetching platform details, if success, carry-on, else throw error
try {
if (_deviceDetails.deviceID != "") {
// post request to server
Map<String, dynamic> requestBody = {
'device_id': _deviceDetails.deviceID
};
http.Response response = await http
.post(Uri.parse(Constants.LOGIN_ENDPOINT), body: requestBody);
_user = userFromJson(response.body);
_deviceDetails.userID = _user.data!.userId!;
_deviceDetails.userName = _user.data!.name!;
_deviceDetails.token = _user.data!.token!;
await _saveLoginDetails(_deviceDetails);
print("[INFO] USER LOGGED IN SUCCESSFULLY");
}
} catch (error) {
print("[INFO] ERROR WHILE FETCHING DEVICE DETAILS: $error");
}
} else {
print("[INFO] THIS USER DEVICE IS ALREADY LOGGED IN");
print("[INFO] FETCHING EXISTING USER DETAILS");
Map<String, dynamic> requestBody = {'device_id': _deviceDetails.deviceID};
http.Response response = await http
.post(Uri.parse(Constants.LOGIN_ENDPOINT), body: requestBody);
_user = userFromJson(response.body);
print("INSIDE LOGIN FUNCTION: ${_user.data!.categoryList!.length}"); // prints 2 in console (correct)
}
_isLoading = false;
notifyListeners();
}
控制台输出:
应用首次加载或热重启时的输出:
I/flutter ( 3495): INITIAL: true
I/flutter ( 3495): INITIAL: 1
I/flutter ( 3495): [INFO] THIS USER DEVICE IS ALREADY LOGGED IN
I/flutter ( 3495): [INFO] FETCHING EXISTING USER DETAILS
I/flutter ( 3495): INSIDE LOGIN FUNCTION: 2
应用程序热重载 (Ctrl+S) 时的输出:
I/flutter ( 3495): INITIAL: false
I/flutter ( 3495): INITIAL: 2
I/flutter ( 3495): INSIDE: false
I/flutter ( 3495): INSIDE: 2
I/flutter ( 3495): INSIDE: false
I/flutter ( 3495): INSIDE: 2
如您所见,热重载后,状态发生了变化,但并非没有,这意味着 notifyListeners()
在 login
函数中的行为不正常?
这里可能有什么问题,我真的很困惑...
非常感谢任何帮助!
Class LogInProvider{
bool _isLogin = false;
setIsLogin(bool isLogin){
_isLogin = isLogin;
notifyListeners();
}
isLogin(){
return _isLogin;
}
}
然后在 ui class .
获取登录信息:
...
child : Consumer<LoginInProvider>(
builder: (context,_loginProvider, child) {
return Text("${_loginProvider.isLogin}");
},
设置登录信息:
Provider.of<LoginInfoProvider>(context).setIslogIn(true);
您需要在等待更新时设置收听true
:
bool isLoading =
Provider.of<LoginProvider>(context, listen: true).isLoading;
User user = Provider.of<LoginProvider>(context, listen: true).user;