Reputation: 1737
I have a method login
in my Provider class which is called in initState()
method of my HomeScreen()
, in login function
I basically register/check if a user information is stored in server or not, and then I post request to server to get that user's info. Everything is working fine but when I hot restart
or reopens
the app, it keeps on loading because obviously the ternary operation doesn't satisfy but If I print the data inside the login
function, it does get changed, so as a result, the notifyListeners()
is not working properly and hence the state is not getting changed. (Right now I have to hot reload
ctrl+s
, and then the state changes and everything loads successfully).
HomeScreen():
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,
)),
);
}
}
(Both courses
and user.data.categoryList
have same length)
Login function in Provider file:
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();
}
Console output:
Output when app first loads or Hot Restart:
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
Ouput when app Hot Reloads (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
As you can see, after hot reloading, the state changes but not without it, so that means notifyListeners()
is not behaving properly in login
function?
What could possible be wrong here, I'm really confused...
Any help would be really appreciated!
Upvotes: 2
Views: 2586
Reputation: 12373
You need to set listen to true
when you are expecting updates:
bool isLoading =
Provider.of<LoginProvider>(context, listen: true).isLoading;
User user = Provider.of<LoginProvider>(context, listen: true).user;
Upvotes: 2
Reputation: 714
Class LogInProvider{
bool _isLogin = false;
setIsLogin(bool isLogin){
_isLogin = isLogin;
notifyListeners();
}
isLogin(){
return _isLogin;
}
}
Then in the ui class .
Get LoginInfo :
...
child : Consumer<LoginInProvider>(
builder: (context,_loginProvider, child) {
return Text("${_loginProvider.isLogin}");
},
SetLogin Info :
Provider.of<LoginInfoProvider>(context).setIslogIn(true);
Upvotes: 0