getx
getx copied to clipboard
GetxService onInit in an error GetLifeCycle
GetxService onInit in an error GetLifeCycle
The problem is that in GetLifeCycleBase, onInit is a Future
the code is at there GetLifeCycleBase
mixin GetLifeCycleBase {
// Internal callback that starts the cycle of this controller.
void _onStart() {
if (_initialized) return;
onInit(); // <--- The problem here is that in GetLifeCycleBase,
_initialized = true;
}
}
example:
class DbService extends GetxService {
Future<DbService> onInit() async { /// onInit is Future<dynamic> Function()
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('FimberLoggerService', () {
setUpAll(() async {
// Get.putAsync(DbService());
/// ⬆️ The signature and usage of this function do not match the documentation https://github.com/jonataslaw/getx/blob/master/README.md#getxservice
/// The argument type 'DbService' can't be assigned to the parameter type 'Future<dynamic> Function()'.
/// must to
Get.put(DbService());
/// or
Get.putAsync(() async => DbService());
})
test("Get DbService", () {
DbService db = Get.find(); // <--- onInit not finish
})
}
To Reproduce run the test case
Expected behavior
Get.putAsync may get the onInit finish OR just like doc call onInit MANUAL
Now this code can work, but it is very cumbersome
class DbService extends GetxService {
Future<DbService> onInit() async {
if(_initialized) return this;
print('$runtimeType delays 2 sec');
await 2.delay();
print('$runtimeType ready!');
return this;
_initialized = true;
}
bool _initialized = false;
}
// in test group
setUpAll(() async {
await Get.putAsync(() async {
GetxService service = GetxService();
await service.onInit();
return service;
});
})
Getx Version:
dependencies:
get: ^4.6.6
Describe on which device you found the bug: In test case
this code is work for me but not elegant:
import 'package:get/get.dart';
import 'package:flutter_test/flutter_test.dart';
abstract class AppService<T extends GetxService> extends GetxService {
@override
Future<T> onInit() async {
if (_initialized) return this as T;
super.onInit();
await init();
_initialized = true;
return this as T;
}
Future<void> init() async => throw UnimplementedError();
bool _initialized = false;
}
class DBService extends AppService {
@override
Future<void> init() async {
/// do sth. only called once
}
}
void main() {
setUpAll(() async {
await Get.putAsync(() => DBService().onInit());
DBService db = Get.find();
/// do sth. with DBService instance
});
}
Thanks for opening this issue, and you're absolutely right!
This is an architectural problem that I didn't think about at the time I created putAsync, to be honest, I used exactly the code you sent (I believe you've seen something like this on discord) for many years. About a year ago I created a Wrapper that allows me to do this in a more elegant way, I believe I can insert it into the package.