Flutter Await Callback Not Give Any Response - dart

I am still a beginner on dart flutter, now I am trying to retrieve data from the REST API and socket.IO. at this time I have a confusing problem, I have tried searching on the internet for 3 days, but there is no solution. I have async and await scripts, but the function I added await doesn't give any response and still pause.
it is assumed that I have two different files, the first is the main file and the second is the helper file.
main.dart
Future<List<ChatTile>> fetchChat(socketutil,id) async {
socketutil.join(id); //STACK IN HERE
SharedPreferences prefs = await SharedPreferences.getInstance();
String messagePrefs = prefs.getString('messagePrefs');
print("DUA");
return await compute(parseListChat, messagePrefs);
}
helper.dart
Future<void> join(String id_room) async {
String jsonData ='{"room_id" : "$id_room","user_id" : "5a91687811138e74009839c9","user_name" : "Denis Muhammad Ramdan","user_photo" : "photo.jpg","user_status" : "1"}';
socketIO.sendMessage("join", jsonData, null);
//subscribe event
return await socketIO.subscribe("updateMessageList", (result) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('messagePrefs', result);
print('SATU');
return await result;
});
}
my question is there something wrong with my code, and how is the best way?
many thanks,

I suggest you to add await_only_futures to your analyzer config
analysis_options.yaml
lint:
rules:
- await_only_futures
You also don't need to do return await something since your function already return a future, this is redondant.
And from what I see of the socketio subscribe method, it does not return the result like you expect but use a callback and does not return it (https://pub.dartlang.org/documentation/flutter_socket_io/latest/flutter_socket_io/SocketIO/subscribe.html)
to handle this you should use a Completer
final completer = Completer<String>()
socketIO.subscribe("updateMessageList", (result) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('messagePrefs', result);
socketIO.unSubscribe("updateMessageList");
completer.complete(result);
});
return completer.future;
you probably want to handle error when there is using completer.completeError(error)
Update
You can alos convert the subscription to a Dart Stream to handle more case.
StreamController<String> controller;
Stream<String> get onUpdateMessageList {
if (controller != null) return controller.stream;
constroller = StreamController<String>.broadcast(
onCancel: () => socketIO.unSubscribe("updateMessageList"),
);
socketIO.subscribe("updateMessageList", constroller.add);
return controller.stream;
}
Future<StreamSubscription> join(String id_room) async {
...
return onUpdateMessageList.listen((result) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('messagePrefs', result);
});
}

Related

how to make singleton class with some initialization code?

I have tried the answers in here How do you build a Singleton in Dart?
but I can't achieve what I want. so basically I want to make a Shared Preference Service as a singleton class. currently my code is like this. this is just a regular class, not a singleton.
class SharedPreferenceService {
late SharedPreferences _prefs;
SharedPreferenceService() {
SharedPreferences.getInstance().then((value) => _prefs = value);
}
Future<void> setIntroPagesHaveBeenViewed() async {
await _prefs.setBool(SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
return _prefs.getBool(SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}
I need a singleton class, but when the instance is initialize for the first time, I also need to initialize _pref , so then I can access that _pref on the methods
Your problem is that initialization is asynchronous.
That means that the first time the singleton instance is accessed, that access needs to be asynchronous too (and so does any further access which happens before the initialization completes). However, the usage pattern of a singleton like this is such that you don't know which access is the first. So you have to make every access asynchronous.
Example:
class SharedPreferenceService {
static final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Future<void> setIntroPagesHaveBeenViewed() async {
await (await _prefs).setBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
return (await _prefs).getBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}
If all the methods are asynchronous anyway, that extra delay is not going to be a problem.
If you really, really only want to do that extra await if absolutely necessary,
you can cache the value, like you try to here:
class SharedPreferenceService {
static final Future<SharedPreferences> _prefsFuture = SharedPreferences.getInstance();
static SharedPreferences? _prefs;
Future<void> setIntroPagesHaveBeenViewed() async {
var prefs = _prefs ??= await _prefsFuture;
await _prefs.setBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
var prefs = _prefs ??= await _prefsFuture;
return _prefs.getBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}

How to add two number fetched from SharedPreferences in Flutter

I was trying to add two numbers say point1 and point2. These points are stored in SharedPreferences .
I have fetched the points using a function Future<int> fetchPoints which is in below.
Then I called this from another function
fetchPoints:
Future<int> fetchFromSps(String field) async {
SharedPreferences sp = await SharedPreferences.getInstance();
return sp.getInt(field);
}
GetPoints:
Future<void> setPoints() async{
int _newPoints=await ((await fetchFromSps('point1'))+(await fetchFromSps('point2')));
setState(() {
_totalPoints=_newPoints.toString();
});
}
setInSharedPreference:
void setInSharedPreference() async{
SharedPreferences prefs=await SharedPreferences.getInstance();
prefs.setInt('point1', 0);
prefs.setInt('point2',0);
}
The function setInSharedPreference is in another dart file,which contains main function
I need to add two points which is named 'point1 and 'point2' from shared preference
just call them from any method like this sample:
fetchTwoPoints() async {
final point1 = await fetchFromSps("point1");
final point2 = await fetchFromSps("point2");
setState(() {
_totalPoints= (point1 + point2).toString();
});
}
Update your setInSharedPreference method because you are using async you need to wait to store the data.
Future<void> setInSharedPreference() async{
SharedPreferences prefs=await SharedPreferences.getInstance();
await prefs.setInt('point1', 0);
await prefs.setInt('point2',0);
}

How to use await instead of .then() in Dart

I'm having the following lines in a Flutter app. _devicesRef refers to some node in a Firebase Realtime Database.
_devicesRef.child(deviceId).once().then((DataSnapshot data) async {
print(data.key);
var a = await ...
print(a);
}
These lines work fine. Now I want to use await instead of .then(). But somehow, once() never returns.
var data = await _devicesRef.child(deviceId).once();
print(data.key);
var a = await ...
print (a);
So print(data.key) is never called.
What's wrong here?
It could be explained by the code following your snippet. Perhaps the future completion is trigger by something after your code and transforming your code with await will wait until a completion that never happens.
For instance, the following code works:
main() async {
final c = Completer<String>();
final future = c.future;
future.then((message) => print(message));
c.complete('hello');
}
but not this async/await version:
main() async {
final c = Completer<String>();
final future = c.future;
final message = await future;
print(message);
c.complete('hello');
}
If you intend to use await as a replacement of .then() in your snippet, this is how you can accomplish it:
() async {
var data = await _devicesRef.child(deviceId).once();
print(data.key);
var a = await ...
print(a);
}();
By placing the code in the asynchronous closure () async {}(), we are not preventing execution of the code that comes after, in a similar fashion to using .then().
it should be encased in an async function like this to use await
Furtre<T> myFunction() async {
var data = await _devicesRef.child(deviceId).once();
return data;
}

Flutter Future returns null

I've seen this already: https://stackoverflow.com/a/49146503/1757321
Followed the solution, but it is not working in my case.
Some enlightenment would do for me this afternoon
Future<String> loadInterest() async {
print('Going to load interests');
final whenDone = new Completer();
SharedPreferences prefs = await SharedPreferences.getInstance();
final token = await prefs.getString('token');
print('The token ${token}');
await this.api.interests(token).then((res) {
// print('The response: ${res['interests']}'); <-- this prints response alright. Data is coming.
whenDone.complete(res['interests']);
});
return whenDone.future;
}
Then I'm trying to use the above Future in a future builder like so:
new FutureBuilder(
future: loadInterest(),
builder: (BuildContext context, snapshot) {
return snapshot.connectionState == ConnectionState.done
? new Wrap(
children: InterestChips(snapshot.data),
)
: Center(child: CircularProgressIndicator());
},
),
Where InterestChips(...) is this:
InterestChips(items) {
print('Interest Chips ${items}');
List chipList;
for (Object item in items) {
chipList.add(Text('${item}'));
}
return chipList;
}
But, I always get null as the snapshot, which means the loadInterest() for the Future is not returning anything.
If I understand this answer correctly, then I'm doing mine along the lines of that: https://stackoverflow.com/a/49146503/1757321
You don't need to use a Completer for this. Since your method is already async, you should just do this for your first code block:
Future<String> loadInterest() async {
print('Going to load interests');
final whenDone = new Completer();
SharedPreferences prefs = await SharedPreferences.getInstance();
final token = await prefs.getString('token');
print('The token ${token}');
final res = await this.api.interests(token).then((res) {
// print('The response: ${res['interests']}'); <-- this prints response alright. Data is coming.
return res['interests']);
}
You might also want to check for snapshot.hasError to make sure you're not getting any exceptions in there.

Recommended way from dart team to catch errors when using await in Flutter

I write a lot of async code that uses await to handle Futures.
If I have
() async {
var result = await someFuture();
}
what would be the preferred way to catch errors. Wraping the code in try/catch or doing
() async {
var result = await someFuture().catch(_errorHandler);
}
EDIT:
Also, if I have many await calls in one async method, what is the preferred catch all the errors instead of writing .catchError for eachOne.
() async {
var result = await someFuture();
var result2 = await someFuture2();
var result3 = await someFuture3();
}
According to the Dart docs if you use await wrap it in a try-catch
According to the Dart docs if you use await wrap it in a try-catch
https://dart.dev/codelabs/async-await#handling-errors
The Docs suggest just wrapping in a try-catch
Example code:
try {
print('Awaiting user order...');
var order = await fetchUserOrder();
} catch (err) {
print('Caught error: $err');
}
Reference also has a runnable example https://dart.dev/codelabs/async-await#handling-errors

Resources