Skip to content

Instantly share code, notes, and snippets.

@manikantag
Last active September 24, 2021 17:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save manikantag/18a0cab5ea2423e321aae62e50a3e00d to your computer and use it in GitHub Desktop.
Save manikantag/18a0cab5ea2423e321aae62e50a3e00d to your computer and use it in GitHub Desktop.
Flutter Getx observable assignment in async issue
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(GetMaterialApp.router(
title: 'Test',
initialBinding: BindingsBuilder.put(() => AuthService(), permanent: true),
getPages: [
GetPage(
name: '/',
page: () => const LoginScreen(),
binding: BindingsBuilder.put(() => LoginController()),
),
GetPage(
name: '/home',
page: () => const HomeScreen(),
binding: BindingsBuilder.put(() => HomeController()),
),
],
));
}
// ----- models -----
class AppUser {
final String uid;
final String mobile;
int count = 0;
AppUser({required this.uid, required this.mobile});
AppUser.newUser(String uid, String mobile) : this(uid: uid, mobile: mobile);
AppUser.dummyUser() : this(uid: '', mobile: '');
@override
String toString() {
return {'mobile': mobile, 'uid': uid, 'counter': count}.toString();
}
}
class Teacher extends AppUser {
final String? regId;
Teacher({required String uid, required String mobile, this.regId})
: super(uid: uid, mobile: mobile);
Teacher.newTeacher(String uid, String mobile) : this(mobile: mobile, uid: uid);
}
class Student extends AppUser {
final String? marks;
Student({required String uid, required String mobile, this.marks})
: super(uid: uid, mobile: mobile);
Student.newStudent(String uid, String mobile) : this(uid: uid, mobile: mobile);
}
// ----- Auth service -----
class AuthService extends GetxController {
Rx<bool> isAuthenticated = false.obs;
Rx<int> authCounter = 0.obs;
Rx<AppUser> currentUser = Rx(AppUser.dummyUser());
/* @override
void onInit() {
currentUser = Student.newStudent('Student 1', 'Student 1 mobile').obs; // This is working
super.onInit();
} */
void doStudentLogin() async {
isAuthenticated.value = true;
// currentUser = Student.newStudent('Student 1', 'Student 1 mobile').obs; // This is working
currentUser = await Future.delayed(
const Duration(milliseconds: 10),
() => Student.newStudent('Student 1', 'Student 1 mobile').obs, // This is NOT working
);
print(currentUser);
}
void doTeacherLogin() async {
isAuthenticated.value = true;
// currentUser = Teacher.newTeacher('Teacher 1', 'Teacher 1 mobile').obs; // This is working
currentUser = await Future.delayed(
const Duration(milliseconds: 10),
() => Teacher.newTeacher('Teacher 1', 'Teacher 1 mobile').obs, // This is NOT working
);
print(currentUser);
}
void doLogout() {
isAuthenticated.value = false;
authCounter = 0.obs;
// currentUser = Teacher.newTeacher('Teacher 1', 'Teacher 1 mobile').obs; // This is working
Get.rootDelegate.offNamed('/');
// Get.reset();
// Get.reloadAll(force: true);
// Get.reload<AuthService>();
// Get.deleteAll(force: true);
}
}
// ----- Login controller & page -----
class LoginController extends GetxController {
final authService = Get.find<AuthService>();
bool isLoggedin() => authService.isAuthenticated.value == true;
void doTeacherLogin() {
authService.doTeacherLogin();
Get.rootDelegate.offNamed('/home');
}
void doStudentLogin() {
authService.doStudentLogin();
Get.rootDelegate.offNamed('/home');
}
}
class LoginScreen extends GetView<LoginController> {
const LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Obx(
() => controller.isLoggedin()
? const Text('Already logged in -> Logout (state not cleared)')
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('authCounter: ${controller.authService.authCounter.value}'),
ElevatedButton(
onPressed: controller.doTeacherLogin,
child: const Text('Teacher Login'),
),
ElevatedButton(
onPressed: controller.doStudentLogin,
child: const Text('Student Login'),
),
],
),
),
),
);
}
}
// ----- Home controller & page -----
class HomeController extends GetxController {
final AuthService _authService = Get.find<AuthService>();
final Rx<int> homeCounter = 0.obs;
late final Rx<int> authCounter;
late final Rx<AppUser> currentUser;
@override
void onInit() {
authCounter = _authService.authCounter;
currentUser = _authService.currentUser;
super.onInit();
}
void increment() {
homeCounter.value++;
authCounter.value++;
currentUser.value.count++;
}
void logout() => _authService.doLogout();
}
class HomeScreen extends GetView<HomeController> {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Obx(
() => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Auth counter: ${controller.authCounter.value}'),
Text('Home counter: ${controller.homeCounter.value}'),
Text(
'Current User: ${controller.currentUser.value is Teacher ? 'Teacher' : 'Student'}'),
Text('Current User: ${controller.currentUser.value}'),
ElevatedButton(
onPressed: controller.increment,
child: const Text('Increment counters'),
),
ElevatedButton(
onPressed: controller.logout,
child: const Text('Logout'),
),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(GetMaterialApp.router(
title: 'Test',
initialBinding: BindingsBuilder.put(() => _AuthService(), permanent: true),
getPages: [
GetPage(
name: '/',
page: () => const _LoginScreen(),
binding: BindingsBuilder.put(() => _LoginController()),
),
GetPage(
name: '/teacher',
page: () => const _TeacherHomeScreen(),
binding: BindingsBuilder.put(() => _TeacherHomeController()),
),
GetPage(
name: '/student',
page: () => const _StudentHomeScreen(),
binding: BindingsBuilder.put(() => _StudentHomeController()),
),
],
));
// Set overlay style status bar. It must run after MyApp(), because MaterialApp may override it.
SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, systemNavigationBarColor: Colors.white);
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
}
// ----- Auth service -----
class _AuthService extends GetxController {
// Rx<bool> isAuthenticated = false.obs;
Rx<_AppUser> currentUser = Rx(_AppUser.dummy());
void doTeacherLogin() async {
// isAuthenticated.value = true;
currentUser = await Future.delayed(
const Duration(milliseconds: 200),
() => _Teacher.newTeacher('Teacher 1', 'Teacher 1 mobile').obs,
);
/* currentUser.value = await Future.delayed(
const Duration(milliseconds: 10),
() => Teacher.newTeacher('Teacher 1', 'Teacher 1 mobile'),
); */
// ignore: avoid_print
print(currentUser);
Get.rootDelegate.offNamed('/teacher');
}
void doStudentLogin() async {
// isAuthenticated.value = true;
currentUser = await Future.delayed(
const Duration(milliseconds: 200),
() => _Student.newStudent('Student 1', 'Student 1 mobile').obs,
);
/* currentUser.value = await Future.delayed(
const Duration(milliseconds: 10),
() => _Student.newStudent('Student 1', 'Student 1 mobile'),
); */
// ignore: avoid_print
print(currentUser);
Get.rootDelegate.offNamed('/student');
}
void doLogout() {
// isAuthenticated.value = false;
// currentUser(_AppUser.dummy());
currentUser = _AppUser.dummy().obs;
// Get.reset();
// Get.reloadAll(force: true);
// Get.reload<AuthService>();
// Get.deleteAll(force: true);
Get.rootDelegate.offNamed('/');
}
}
// ----- Login controller & page -----
class _LoginController extends GetxController {
final authService = Get.find<_AuthService>();
// bool isLoggedin() => authService.isAuthenticated.value;
}
class _LoginScreen extends GetView<_LoginController> {
const _LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Obx(() =>
// controller.isLoggedin() ? const Text('Logged in') : const Text('Not logged in')),
// Obx(() => Text('currentUser: ${controller.authService.currentUser.value}')),
ElevatedButton(
onPressed: controller.authService.doTeacherLogin,
child: const Text('Teacher Login'),
),
ElevatedButton(
onPressed: controller.authService.doStudentLogin,
child: const Text('Student Login'),
),
/* ElevatedButton(
onPressed: controller.authService.doLogout,
child: const Text('Logout'),
), */
],
),
),
);
}
}
class _TeacherHomeController extends GetxController {
final authService = Get.find<_AuthService>();
final Rx<_Teacher> currentUser = (Get.find<_AuthService>().currentUser.value as _Teacher).obs;
}
class _TeacherHomeScreen extends GetView<_TeacherHomeController> {
const _TeacherHomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Welcom, Teacher'),
),
body: Container(
color: Colors.lightGreen.shade200,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() => Text('currentUser: ${controller.currentUser.value}')),
ElevatedButton(
onPressed: controller.authService.doLogout,
child: const Text('Logout'),
),
],
),
),
),
);
}
}
class _StudentHomeController extends GetxController {
final authService = Get.find<_AuthService>();
final Rx<_Student> currentUser = (Get.find<_AuthService>().currentUser.value as _Student).obs;
}
class _StudentHomeScreen extends GetView<_StudentHomeController> {
const _StudentHomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Welcom, Student'),
),
body: Container(
color: Colors.lightBlue.shade200,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() => Text('currentUser: ${controller.currentUser.value}')),
ElevatedButton(
onPressed: controller.authService.doLogout,
child: const Text('Logout'),
),
],
),
),
),
);
}
}
// ----- models -----
class _AppUser {
final String uid;
final String mobile;
int count = 0;
_AppUser({required this.uid, required this.mobile});
_AppUser.dummy() : this(uid: 'dummy', mobile: '');
@override
String toString() {
return {'mobile': mobile, 'uid': uid, 'counter': count}.toString();
}
}
class _Teacher extends _AppUser {
final String? regId;
_Teacher({required String uid, required String mobile, this.regId})
: super(uid: uid, mobile: mobile);
_Teacher.newTeacher(String uid, String mobile) : this(mobile: mobile, uid: uid);
}
class _Student extends _AppUser {
final String? marks;
_Student({required String uid, required String mobile, this.marks})
: super(uid: uid, mobile: mobile);
_Student.newStudent(String uid, String mobile) : this(uid: uid, mobile: mobile);
}
@manikantag
Copy link
Author

manikantag commented Sep 24, 2021

Fix is to add await at line 112 & 117.

  void doTeacherLogin() async {
    await authService.doTeacherLogin();
    Get.rootDelegate.offNamed('/home');
  }

  void doStudentLogin() async {
    await authService.doStudentLogin();
    Get.rootDelegate.offNamed('/home');
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment