I am creating an app and I use signalr, I am able to connect to the hub, but it is not possible to invoke a method, every time I get this exception:Unhandled Exception: type 'GeneralError' is not a subtype of type 'Error' in type cast
Here my code:
var hubConnection;
String mobileSession;
Future<void> createSignalRConnection() async {
hubConnection =
new HubConnectionBuilder().withUrl(GLOBAL_BACKEND_SESSION_NEW).build();
await hubConnection.start();
logger.log(Level.INFO, "Connection successful");
hubConnection.onclose((error) {
logger.log(Level.INFO, "Connection Closed");
createSignalRConnection();
});
}
Future<bool> sendParingCode(String pairingCode) async {
final result = await hubConnection
.invoke("RequestPairing", args: [mobileSession, pairingCode]);
logger.log(Level.INFO, "Pairing successful");
return true;
}
void initSession() async {
mobileSession = await hubConnection
.invoke("InitSession");
print(mobileSession);
logger.log(Level.INFO, "Session init successful");
}
I use it like this in a PageState:
void initState() {
super.initState();
createSignalRConnection();
initSession();
}
I think you should wait for createSignalRConnection to be completed before calling invoke method. Try this:
#override
void initState() {
super.initState();
_asyncInitState();
}
Future<void> _asyncInitState() async {
await createSignalRConnection(); // HERE: add await
initSession();
}
Related
Following is my code. I'm trying to get all the 'Babies' which are in documents:
class _HomePageeState extends State<HomePagee> {
String t_babies = getCount().toString();
}
Future getCount() async {
return FirebaseFirestore.instance.collection('Babies').snapshots().length;
}
Instead I get this error: instance of \_future\<int\>
Here is my Database. I expect to get 2 counts:
You need to use await when getting Future values and also you should pass Future and the type Future<int>:
Future<int> getCount() async {
return await FirebaseFirestore.instance.collection('Babies').snapshots().length;
}
and also get the method using await but inside and async function:
void example() async { // <---- here the async you need to add to use await
int babiesLength = await getCount(); // here use await
}
You should use setState to update the string , because the fetch takes time as it involves network.
String t_babies = '';
Future<void> _getCount() async {
setState((){
t_babies = FirebaseFirestore.instance.collection('Babies').snapshots().length.toString();
});
}
#override
void initState() {
super.initState();
_getCount();
}
main() async {
try {
final t = Test();
await Future.delayed(Duration(seconds: 1));
} catch (e) {
// Never printed
print("caught");
}
}
void willThrow() async {
throw "error";
}
class Test {
Test() {
willThrow();
}
}
If the "async" keyword is removed from willThrow everything works as expected.
Is it because you can't await a constructor? If so is there anyway to catch async errors in a constructor body?
Have this a go:
void main() async {
try {
final t = Test();
await Future.delayed(Duration(seconds: 1));
} catch (e) {
// Never printed
print("caught");
}
}
Future<void> willThrow() async {
throw "error";
}
class Test {
Test() {
willThrow().catchError((e){print('Error is caught here with msg: $e');});
}
}
As to the 'why':
You use a normal try/catch to catch the failures of awaited asynchronous computations. But since you cannot await the constructor, you have to register the callback that handles the exception in another way. I think :)
Since you never awaited the Future that was returned from willThrow(), and you never used the result of the Future, any exception thrown by the function is discarded.
There is no way to write an asynchronous constructor. So you are stuck with using old-school callbacks to handle errors, or simulate an async constructor with a static method:
void main() async {
try {
final t = await Test.create();
await Future.delayed(Duration(seconds: 1));
} catch (e) {
// Never printed
print("caught");
}
}
Future<void> willThrow() async {
throw "error";
}
class Test {
Test._syncCreate() {}
Future<void> _init() async {
await willThrow();
}
static Test create() async {
Test result = Test._syncCreate();
await result._init();
return result;
}
}
I have these methods, for some reason fetchItems is being called first before initPosition, how come dart wont wait for it to finish and proceeds to the second method? I've added async/await but it still doesn't work. I've also checked my backend logs to confirm this. Am I doing something wrong?
Future<void> initPosition() async {
if (_latitude != null && _longitude != null) {
await Socket.updatePosition(
lat: 51,
lon: 17,);
}
}
Future<void> initMarkers() async {
await initPosition();
await Provider.of<Items>(context, listen: false)
.fetchItems();
}
void initMapState() async {
await getCurrentLocation().then((_) async {
await initMarkers();
setState(() {
_loaded = true;
});
});
}
#override
void initState() {
super.initState();
_location.enableBackgroundMode(enable: false);
WidgetsBinding.instance?.addPostFrameCallback((_) {
initMapState();
});
}
Future<void> fetchItems() async {
itemList = await repository.getItemList();
notifyListeners();
}
Working with multiple asynchronous functions inside Futures depends on whether one is finished or not, not every single one. For this, you can call the "whenComplete" method so you can assure that your future function have finished running. Like this:
For your initMarkers() function:
Future<void> initMarkers() async {
await initPosition().whenComplete((){
Provider.of<Items>(context, listen: false)
.fetchItems();
});
}
For your initMapState() function:
void initMapState() async {
await getCurrentLocation().whenComplete(() async {
await initMarkers().whenComplete((){
setState(() {
_loaded = true;
});
});
});
}
Keep in mind that, in your code, you are not working with the returning value of your getCurrentLocation() function, so instead of using the "then" method use the "whenComplete" method, assuring that you changed or returned your values with this function. Finally, for the initState(), make the function body with asynchronous:
#override
void initState() {
super.initState();
_location.enableBackgroundMode(enable: false);
WidgetsBinding.instance?.addPostFrameCallback((_) async {
initMapState();
});
}
This should work.
The error should be clear but I'm unsure how to go around it.
Basically I have a Stream builder I'm calling every second by getData() method to update my SfCalendar with new data.
Stream<DataSource> getData() async* {
await Future.delayed(const Duration(seconds: 1)); //Mock delay
List<Appointment> appointments = foo() as List<Appointment>;
List<CalendarResource> resources = bar() as List<CalendarResource>;
DataSource data = DataSource(appointments, resources);
print("Fetched Data");
yield data;
}
But my appointments method foo() is of type Future<List> and not List.
Future<List<Appointment>> foo() async {
var url0 = Uri.https(
"uri",
"/profiles.json");
List<Appointment> appointments = [];
try {
final response = await dio.get(url0.toString());
//final Random random = Random();
//_colorCollection[random.nextInt(9)];
response.data.forEach((key, value) {
appointments.add(
Appointment(
id: int.parse(
value["id"],
),
startTime: DateTime.parse(value["startTime"]),
endTime: DateTime.parse(value["endTime"]),
),
);
});
} catch (error) {
print(error);
}
return appointments;
}
That is what the error should be telling, yes?
I tried removing the Future cast from foo() appointments but then I can't use async.
I also tried returning Future.value(appointments) but same error.
This is where I call my Stream in initState():
#override
void initState() {
super.initState();
print("Creating a sample stream...");
Stream<DataSource> stream = getData();
print("Created the stream");
stream.listen((data) {
print("DataReceived");
}, onDone: () {
print("Task Done");
}, onError: (error) {
print(error);
});
print("code controller is here");
}
Thank you, please help when possible
Just like JavaScript, async functions always return a Future. That's why you can't use async when you remove Future from the return type.
Since you're not waiting for that Future to resolve, you're actually trying to cast a Future to a List, which isn't a valid cast. All you should need to do is wait for the function to finish so it resolves to a List:
List<Appointment> appointments = await foo() as List<Appointment>;
and, since your return type is Future<List<Appointment>>, you don't actually need to cast the result.
List<Appointment> appointments = await foo();
in my main.dart i have among others those two functions:
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
}
And
#override
void initState() {
super.initState();
_fetchMasterData();
}
What i would like to have is to wait in initState till _fethcMasterData is done bevore Widgert build is called.
Is that possible? Many thanks for any help!
Here how I use an async func in initstate;
builder() async {
favoriteDatabase =
await $FloorFavoriteDatabase.databaseBuilder('favorite_database.db')
.build();
setState(() {
favoriteDao = favoriteDatabase.favoriteDao;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
getNamePreferences().then(updateName));
});
builder();
favoriteDao.findAllMoviesAsStreamW();
favoriteDao.findAllMoviesAsStream();
}
Also you can check this mini article too.
It is not possible to await in initState, so when you finish all loading process then you can call SetState method which populate your widget with actual data.
Second solution could be use of futurebuilder or streambuilder where you want to show data but it is only possible if any methods data is not dependent on each other.
Future<void> _fetchMasterData() async {
print("Start fetch");
var jwt = await API.attemptLogIn();
if (jwt != null) {
Map<String, dynamic> answer = jsonDecode(jwt);
if (answer['message'] == 'Auth ok') {
jwtToken = 'Bearer ' + answer['token'];
}
}
await _getArticles();
await _getMainCategories();
await _getIngredients();
await _getArticleIngredients();
print("EndMasterData fetch");
SetState((){}); // added line
}