variable with late modifier not getting initialized - flutter

Here is my provider code for connectivity, where the variable _isOnline will be assigned later.
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
class ConnectivityProvider with ChangeNotifier {
// this will hold the status
late bool _isOnline;
// method to set the initial state and listen
Future<void> updateStatus() async {
// getting the object
Connectivity connectivity = Connectivity();
// getting the status
final ConnectivityResult connectivityResult =
await connectivity.checkConnectivity();
if (connectivityResult == ConnectivityResult.none) {
_isOnline = false;
} else {
_isOnline = true;
}
}
// getter to get the online status
bool get isOnline => _isOnline;
}
I'm assigning the value to the _isOnline in another page's initState:
#override
void initState() {
super.initState();
// getting the initial status of the connection
Provider.of<ConnectivityProvider>(context, listen: false).updateStatus();
}
But I'm still getting an error saying that the variable was not initialized even though I did assign it in the initState:
Can someone please tell me what I'm doing wrong here?

The issue appears because somewhere in your codes call the isOnline when it is still not initialized. You can just change the variable from late bool _isOnline; to bool _isOnline = false; to make sure the internet is not connected as default when users open the app.

Related

SharedPrefrences delay before initializing - Flutter

I'm using Shared preferences to save the user's name and login state even after closing the app. the Shared Preference I used in main.dart is fine because I used it in the main function and made it async, but when I'm trying to use it in other classes, I see a dark red screen for less than a second before loading the page and it makes my app so ugly. what can I do to fix it?
Here's my code:
late bool _isEditingText;
TextEditingController _editingController = TextEditingController();
late String initialText ;
SharedPreferences? _prefs;
#override
void initState(){
super.initState();
initializePreference().whenComplete((){
setState(() {});
});
}
Future<void> initializePreference() async{
_prefs = await SharedPreferences.getInstance();
String? name = _prefs?.getString('name');
if (name == null) {
_isEditingText = true;
initialText = 'Enter ur name';
} else {
_isEditingText = false;
initialText = name;
}
}
Update:
sorry for not including my exact error... here it is :
LateInitializationError: Field '_isEditingText#37486951' has not been initialized.
I think you are performing setState before all widgets are get initialised. So for that you can update initState as below:
void initState(){
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) async {
initializePreference().whenComplete((){
setState(() {});
});
});
}
If it's not causing issue, than you have to show loading indicator. Like initially when there is no data indicator will be there and once you get data from SharedPreference in setState - you have to remove indicator and load your data.
You can use CircularProgressIndicator for that.
initialise your boolean variable,
var isDataLoad = false;
once you get data in whenComplete(), set it as true and based on this variable you can declare your widgets.
isDataLoad ? Container( // Your widgets where you use "initialText" ) : CircularProgressIndicator();

Flutter stream does not update global variable

On my firebase server i have a document which contains a bool field with the value "true"
I created a stream to listen for this value:
final CollectionReference _ref = FirebaseFirestore.instance.collection('collection');
Stream? getValue;
bool value = false;//Global variable
void initState() {
super.initState();
getValue = _ref.doc().collection("list").doc().snapshots();
getValue.forEach((element){
value = element["value"];
print(value);//Shows the correct value if it changes
});
}
//Somewhere else in the code but in the same class
print(value);//Shows always false even if i change it on firebase to true and i don`t know why?
Let meh know if you needmore information, Thank you!
To update your value in a StatefulWidget, you should wrap with a setState.
_ref.doc().collection("list").doc().snapshots().listen((element) {
if (!mounted) {
return;
}
setState(() {
value = element["value"];
});
});

Mocking GetStorage for testing in flutter

I am unit testing and widget testing my code. I have tried mokito and moktail to mock the Get storage but get this error:
package:get_storage/src/storage_impl.dart 47:7 GetStorage._init
===== asynchronous gap ===========================
package:get_storage/src/storage_impl.dart 28:7 new GetStorage._internal.<fn>
the class that I am testing:
class ShowCaseController extends GetxController {
final box = GetStorage();
displayAnySC(String playKey, String replayKey, GetStorage box) async {
bool? showcasePlayStatus = box.read(playKey);
if (showcasePlayStatus == null) {
box.write(playKey, false);
// box.remove(replayKey);
box.write(replayKey, false);
return true;
}
bool? showcaseReplayStatus = box.read(replayKey);
if (showcaseReplayStatus == null) {
box.write(replayKey, false);
return true;
}
return false;
}
}
here is one empty simple test using mock that gives error:
class MockStorage extends Mock implements GetStorage {}
void main() {
group('Show case controller', () {
final showCaseCnt = ShowCaseController();
late bool _data;
late MockStorage _mockStorage;
setUp(() {
_mockStorage = MockStorage();
_data = showCaseCnt.displayAnySC('playKey', 'replayKey', _mockStorage);
});
test(
'displayAnySC should return false when the play and replay are not null',
() {
});
});
}
I have tried #GenerateMocks([ShowCaseController]) and also added GetStorage.init() inside the main function of the test but got the same error.
P.S. I haven't seen any article or question related to mocking the GetStorage for test in Flutter. Appreciate any explanation or link that helps in this regard.
I am using the GetX package for dependency injection and state management. And using the GetStorage package for keeping the theme persistent and storing keys for notifying the app to play or replay ShowCaseView.

Flutter: Non-nullable instance field 'currentLocation' must be initialised

I'm getting an error with the new flutter changes on null safety. Am not sure whether I am supposed to add final/late/! in this code.
I have a code to connect to Google Maps and now I want to be able to store the data collected.
Right now I facing an error at the Application Bloc: Non-nullable field 'currentLocation' must be initialized.
import 'package:flutter/material.dart';
import 'package:hawkepedia/services/geolocator_Services.dart';
import 'package:geolocator/geolocator.dart';
class ApplicationBloc with ChangeNotifier {
final geoLocatorService = GeolocatorService();
//Variables
Position currentLocation;
//fire function when the app starts
ApplicationBloc(){
setCurrentLocation();
}
//gets current location
setCurrentLocation() async {
currentLocation = await geoLocatorService.getCurrentLocation();
notifyListeners();
}
}
As it is state in the error, the field causing the issue is currentLocation.
You can:
set it as late meaning you will initilize it during initState for example.
set it a nullable, not sure it is possible in this case, Position? currentLocation. (But it is for primary types)
Initialize it with a neutral value that you know is not initialized yet
Edit:
import 'package:flutter/material.dart';
import 'package:hawkepedia/services/geolocator_Services.dart';
import 'package:geolocator/geolocator.dart';
class ApplicationBloc with ChangeNotifier {
final geoLocatorService = GeolocatorService();
//Variables
late Position currentLocation;
//fire function when the app starts
ApplicationBloc(){
setCurrentLocation();
}
//gets current location
setCurrentLocation() async {
currentLocation = await geoLocatorService.getCurrentLocation();
notifyListeners();
}
}

How to get the 'bool' value from a Future<bool> into a field variable, for later use

I am using flutter_blue package for using the Bluetooth service. I want to check whether the device has Bluetooth capabilities. The method isAvailable seems to do it. However, it returns a Future<bool>, which I am tryting to get into a variable as follows:
import 'package:flutter_blue/flutter_blue.dart';
class BT_Base {
final FlutterBlue _fb = FlutterBlue.instance;
bool BTAvailable = true; // as a default placeholder
BT_Base () {
BTAvailable = _fixAvail();
}
_fixAvail () async {
return await _fb.isAvailable;
}
...
I try to get the future value from it and store into BTAvailable. Later on, I use the fixed BTAvailable field to get the appropriate Widget to be passed onto as follows:
class BTDevicePrompt extends StatelessWidget {
#override
Widget build(BuildContext context) {
BT_Base bt = BT_Base();
var btDeviceRes = bt.scan();
if(!bt.BTAvailable) return Text('Bluetooth unavailable on device...');
else if (btDeviceRes.isEmpty) return Text('No Bluetooth devices in range...');
else {
return CupertinoActionSheet(
actions: [
...
],
)
}
}
}
But I keep getting the error type 'Future<dynamic>' is not a subtype of type 'bool' at runtime. How can I use the Future properly in this situation? It is alright if the whole process just halts and waits for this part as well.
I have gone through a lot of solutions but I am not able to piece it together.
Any method marked async always returns a Future of some kind. You can give it an explicit return type like Future<bool> function() async { ... }, or if you leave it out it will infer Future<dynamic>.
In short, you can't get a bool from a Future<bool> outside of an async function (there are technically ways but almost certainly not what you want in Flutter).
This makes sense, since the whole point of a Future<bool> is that it's going to be a bool in the future. If there was some process to convert from a Future<bool> to a bool, what should it do if the future has not yet completed? Perhaps it should wait until it has completed. In that case, you're just describing the await keyword.
If, however, you want to use a Future in your UI in a Flutter application, you have a few options.
The simplest for your case will be to move it into initState():
class BTDevicePrompt extends StatefulWidget {
// stateful widget boilerplate
}
class BTDevicePromptState extends State<BTDevicePrompt> {
bool isAvailable = false;
#override
void initState() {
super.initState();
checkAvailable(); // use a helper method because initState() cannot be async
}
Future<void> checkAvailable() async {
// call an async function and wait for it to complete
bool result = await checkIfBluetoothAvailable();
setState(() => bluetoothAvailable = result); // set the local variable
}
#override
Widget build(BuildContext context) {
if (bluetoothAvailable) return Text('bluetooth available');
else return Text('bluetooth not available');
}
}