Completer Flutter hook causes bad state error - flutter

For managing pull-to-refresh indication in Flutter with BLoC I created a custom Completer hook as an alternative to using a Stateful Widget, and in general, it works fine, however with hot-reload I run into Bad state: Future already completed
import 'dart:async';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class _CompleterHook extends Hook<Completer> {
#override
HookState<Completer, Hook<Completer>> createState() => _CompleterHookState();
}
class _CompleterHookState extends HookState<Completer, _CompleterHook> {
Completer _completer;
#override
void initHook() {
_completer = Completer<void>();
super.initHook();
}
#override
Completer build(BuildContext context) => _completer;
}
Completer<void> useCompleterHook() {
return Hook.use(_CompleterHook());
}
Not sure if there is perhaps something I missed, it's literally only on the HR so completely a development annoyance, I would prefer not to learn to live with it though. Any ideas or suggestions on ways to fix that.
TIA

Related

Is creating a stateful widget with a generic data type <T> passed to the state in Flutter a good practice?

I have created a widget in Flutter as follows:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class WidgetA<T> extends StatefulWidget {
const WidgetA({
super.key,
required this.errorSelector,
...
});
final Function errorSelector;
...
#override
State<WidgetA> createState() =>
_WidgetAState<T>();
}
class _WidgetAState<T> extends State<WidgetA> {
...
#override
Widget build(BuildContext context) {
...
return Builder(
builder: (ctx) {
final String foo =
ctx.select(widget.errorSelector as String Function(T));
return Text(foo);
}
);
}
}
Is this practice okay?
Are there better ways to accomplish this?
Can this cause any issues?
FYI - T is being used to pass a Class that extends a Bloc.
it's not bad and it's not good unless you have a good reason to do it (for example if you want to customize a data type based on that generic ).
so before doing it, ask yourself why so I need to make it generic, all the good patterns in the code are there to add some value to the code.
as you can see the only place where the generic is important is to set it in the State object, this prevents conflicting your StatefulWidget in your app with others and specify it to one StatefulWidget

LateInitializationError... has not been initialized

Wondering if anyone can help with the
LateInitializationError: Field'_user#582204964' has not been initialized. when running on the emulator in android studio.
Briefly, I am absolutely new to Flutter and dart. I have been using a tutorial to work along however, unfortunately, a lot of the code has been deprecated and there is no update to the course tutorial. In which case I have been finding the new "methods" and wording to be able to continue with the course and so far so good. However I am stumped at this point with the above error message.
I have put the code that i think is the offending one and hope that someone can point me in the right direction. please take it easy on me as i said I am new and learning to navigate taking baby steps.
thanks in advance.
import 'package:flutter/material.dart';
import 'package:time_tracker/app/sign_in/sign_in_page.dart';
import 'package:firebase_auth/firebase_auth.dart';
class LandingPage extends StatefulWidget {
#override
_LandingPageState createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
late var _user;
void _updateUser (User user){
initUser().whenComplete((){
setState(() {});
});
setState(() {
// _user = user;
});
}
#override
Widget build(BuildContext context) {
if (_user == null){
return SignInPage(
onSignIn: _updateUser,
);
}
return Container(); // Temporary placeholder for homepage
}
}
initUser() {
}
You have comment out the line in which you were initializing the value of user inside the setState((){}) function.

How to use didChangeAppLifecycleState with Flutter Hooks

I am using Flutter with hooks and I am trying to get the App Life Cycle State. I followed documentation and created new hook (code shown below) which works ok for all situations with one exception. When the application state becomes "paused", the hook does not return the value back to the widget. I am not clear what to do at this point. Someone suggested using Isolates but I don't see how that can help. Updating App Life Cycle is not compute expensive.
Please let me know what else I could do make this work.
Thanks
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
AppLifecycleState useAppLifecycleState() {
return use(const _LifeCycleState());
}
class _LifeCycleState extends Hook<AppLifecycleState> {
const _LifeCycleState();
#override
__LifeCycleState createState() => __LifeCycleState();
}
class __LifeCycleState extends HookState<AppLifecycleState, _LifeCycleState>
with WidgetsBindingObserver {
AppLifecycleState _state;
#override
void initHook() {
super.initHook();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
#override
AppLifecycleState build(BuildContext context) {
return _state;
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_state = state;
});
super.didChangeAppLifecycleState(state);
}
}
Thanks for your help.

Flutter bloc - Getting data from DB asynchronously

I am making an app using the BLoC architecture using the flutter_bloc package, but I need to get data from a database, which is asynchronous, meaning I can't initialize the BLoC with data from my database. Is there a way I can do this? My BLoC class text is
import 'package:countdown/database/utils.dart';
import 'package:countdown/events/countdown_event.dart';
import 'package:countdown/models/countdown.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class HomeBloc extends Bloc<CountdownEvent, List<Countdown>> {
#override
// TODO: implement initialState
List<Countdown> get initialState => DatabaseUtils.getCountdowns();
#override
Stream<List<Countdown>> mapEventToState(CountdownEvent event) {
}
}
I know this is very similar to This Question, but that question's answers don't have any code snippets which would be very helpful.
create one separate async function and call if from initState(). this is my code you can call your method according to use.
#override
HomeState get initialState {
_checkLocationSettings();
return InitialHomeState();
}
_checkLocationSettings() async {
locationUpdateSetting = await repository.isLocationUpdateOn();}

Flutter GetIt Plugin - No type xxx is registered inside GetIt

I set everything up as shown in the example project:
import 'package:get_it/get_it.dart';
import 'package:places/services/authService.dart';
final locator = GetIt.instance;
void setupLocator() {
locator.registerSingleton<AuthService>(AuthService());
print("registered");
}
with the call in the main file
void main() {
setupLocator();
runApp(MyApp());
}
I have some Check where the locator also correctly return my AuthService
class AuthGuardView extends StatefulWidget {
AuthGuardView({Key key}) : super(key: key);
#override
_AuthGuardViewState createState() => _AuthGuardViewState();
}
class _AuthGuardViewState extends State<AuthGuardView> {
#override
Widget build(BuildContext context) {
return ViewModelProvider<AuthGuardViewModel>.withConsumer(
viewModel: AuthGuardViewModel(),
onModelReady: (model) => model.initialise(),
builder: (context, model, child) => model.isLoggedIn
? Container(
color: Colors.white,
child: Text("Logged In"),
)
: SignUpView(),
);
}
}
class AuthGuardViewModel extends ChangeNotifier {
AuthService _authService = locator<AuthService>();
bool isLoggedIn = false;
void initialise() async {
isLoggedIn = await _authService.isLoggedIn();
notifyListeners();
}
}
If I do the exact same thing inside the ViewModel for the SignUpView I get the following error
flutter: The following assertion was thrown building SignUpView(dirty, state: _SignUpViewState#01129):
flutter: No type AuthService is registered inside GetIt.
flutter: Did you forget to pass an instance name?
flutter: (Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;did you
flutter: forget to register it?)
flutter: 'package:get_it/get_it_impl.dart':
flutter: Failed assertion: line 248 pos 14: 'instanceFactory != null'
In the ViewModel for the AuthGuard I do successfully retrieve the auth service. I also commented out the locator code (because I thought it might be the async call or something like that) but the same error persists.
I am using get_it: ^4.0.1 but the error persists when downgrading to 3.x.x
Here the SignUpViewModel
class SignUpViewModel extends ChangeNotifier {
SignUpViewModel(){
if(locator.isRegistered<AuthService>()) {
AuthService _authService = locator<AuthService>();
}
}
var textInputFormatter = [
WhitelistingTextInputFormatter(RegExp(r'\d')),
PhoneNumberTextInputFormatter()
];
var textEditingController;
var context;
}
This happens when the class to be registered as singleton has async methods. To fix this you need to await the singleton to be fully generated before runApp() is ran.
void main() async {
/* WidgetsFlutterBinding.ensureInitialized() is required in Flutter v1.9.4+
* before using any plugins if the code is executed before runApp.
*/
WidgetsFlutterBinding.ensureInitialized();
// Configure injecction
await setupLocator();
runApp(MyApp());
}
Adding this answer, as I think it might help others!
I have faced the same issue earlier. For me, it was due to an ordering issue. So make sure to initiate/declare the dependency objects first and then instantiate/declare the dependent one.
Using the latest get_it version in pubspec.yaml ( now it is get_it: ^4.0.2 ) resolve the issue for me.
I have also faced this issue. Nothing made sense. Then I remembered, that I recently did case sensitive renaming.
I changed i.e. Services/Database/Database.dart to services/database/database.dart, but in one file, I used import with the lowercased version, while in the other, it still was the uppercased version. Making the case consistent throughout the project was the fix I needed.