I am getting Future instance while getting sharedPreference value as follows
Future<int> getCounterValue() async{
SharedPreferences preferences= await SharedPreferences.getInstance();
return preferences.getInt("counter") ;
}
Then I want to get int value from that Future instance. Please help thanks in advance.
There is no way to get back from async execution to sync execution.
You can only get the value by using await or .then((param) { print(param); })
You would need to provide more context to make a concrete suggestion about how to solve your actual problem.
For non-async method:
void methodSync() {
getCounterValue().then(
(value){
// do something with value
print(value);
}
);
}
For async method:
void methodAsync() async{
int value = await getCounterValue();
// do something with value
print(value);
}
Related
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;
}
}
In Dart, if you have an async function that doesn't return anything, should it return Future<void> or simply void? Both seem to work, but why?
void foo() async {
print('foo');
}
Future<void> bar() async {
print('bar');
}
void main() async {
await foo();
await bar();
print('baz');
}
Compiles with no errors or warnings and prints
foo
bar
baz
In your code, both functions foo() and bar() are not returning anything so any function return type is valid for both functions eg:
void/T/Future<T>... foo() async {
print('foo');
}
Future<void>/T/Future<T>... bar() async {
print('bar');
}
and here,
await foo();
await bar();
await just waits till the execution of these async functions is complete. As there is no return type, await has no purpose here(redundant) so this is and should not be a compilation error.
The difference is that Future<void> gives you information of the execution of the function like when the execution is complete and it also allows you to specify what to do when the function is executed by using bar().then(...) and bar().whenComplete(...).
While foo() function return void and void does not hold as such any info like Future<void>. If you try to await bar() it will convert that Future object from Future<void> to void.
Future is just a container, with await returns the values once the async "tasks" are completed. Without await, Future objects give you information about the execution of the function from which they are returning.
Thanks to the other answers - they were a little unclear to me so I'm just going to add some clarifications after experimenting on DartPad:
It is never an error or even a warning! to not return a value from a function, irrespective of the return type. This madness is presumably inherited from Javascript.
If you don't return from a function it implicitly returns null. Except in these cases:
If the return type is void, it does not return a value (and using the result of the expression is a compiler error).
If the function is async:
If the return type is void, you cannot use the result of the function, however you can still await it but you cannot use the result of the await expression, or use any methods of Future.
If the return type is Future<void> it returns an instance of Future<void>. You can await it, and call methods of Future, e.g. .then((void v) { ... });. However you cannot use the result of await (because it is void).
If the return type is Future<T> it returns an instance of Future<T> that resolves to null.
So basically, if you want to allow callers to use Future methods, you need to annotate the return type as Future<void>. If you merely want them to be able to await the function, you only need void. However since you probably don't know in advance I suspect it is a good idea to always use Future<void>.
Here's an example that demonstrates the possibilities:
// Compilation error - functions marked async must have a
// return type assignable to 'Future'
// int int_async() async {
// }
void void_async() async {
}
Future<void> future_void_async() async {
}
Future<int> future_int_async() async {
}
int int_sync() {
}
void void_sync() {
}
Future<void> future_void_sync() {
}
Future<int> future_int_sync() {
}
void main() async {
// print('${void_async()}'); // Compilation error - expression has type void.
print('future_void_async: ${future_void_async()}');
print('future_int_async: ${future_int_async()}');
// print('${await future_void_async()}'); // Compilation error.
await future_void_async();
future_void_async().then((void v) {
print('ok');
});
await void_async();
// void_async().then((void v) { // Compilation error.
// print('ok');
// });
print('await future_int_async: ${await future_int_async()}');
print('int_sync: ${int_sync()}');
// print('${void_sync()}'); // Compilation error - expression has type void
print('future_void_sync: ${future_void_sync()}');
print('future_int_sync: ${future_int_sync()}');
}
It prints
future_void_async: Instance of '_Future<void>'
future_int_async: Instance of '_Future<int>'
ok
await future_int_async: null
int_sync: null
future_void_sync: null
future_int_sync: null
A Future is simply a representation of an Object that hasn't completed the underlying function, and thus is a "promise" for later use. When you use Future<void>, there's no Object to return anyways, so it doesn't matter whether you use void or Future<void>. (The function doesn't return anything, so the return type is a placeholder anyways.)
However...
Future<void> can be used for listeners, and to check when things are complete, as can every Future. This means that you can use Future's listeners to check for completion or errors in running your Future<void> async function, but not your void async function. Thus, in some cases, it's better to give Future<void> than void as the return type.
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);
});
}
I'm trying to push a route to display a ListView item when that item is tapped (onTap). The onTap property for InkWell is defined as a VoidCallback. However, I would like to be able to receive a return value from the callback, indicating whether the user has modified said item in the dialog that was opened.
Assigning a Future<Null> async function to onTap seems to be OK, as per the Shrine Demo (shrine_home.dart in the flutter_gallery example):
Future<Null> _showOrderPage(Product product) async {
final Order order = _shoppingCart[product] ?? new Order(product: product);
final Order completedOrder = await Navigator.push(context, new ShrineOrderRoute(
order: order,
builder: (BuildContext context) {
return new OrderPage(
order: order,
products: _products,
shoppingCart: _shoppingCart,
);
}
));
assert(completedOrder.product != null);
if (completedOrder.quantity == 0)
_shoppingCart.remove(completedOrder.product);
}
Why and how is this working? Thanks.
Dart allows you to use a function with a non-void return value as a function with a void return value. The function will still return values as normal, but the analyzer will infer that they're of the void type and will complain if you try to use them, unless you cast them back to something else.
typedef void VoidCallback();
typedef int IntCallback();
final IntCallback i = () => 42;
void main() {
final VoidCallback v = i;
print("${v()}"); // prints 42
print(v() as int); // also prints 42
print(v().toString()); // also prints 42, but analyzer complains:
// method 'toString' isn't defined for class 'void'
}
That is why you can use a function that returns a Future<Null> as a VoidCallback.
Oops. Just realized the assignment was actually via a lambda, which is a VoidCallback:
onPressed: () { _showOrderPage(product); }
Still - it seems to be working for me in another place, where I assign a Future<Null> async function to the onPressed method of FloatingActionButton...
Consider this example:
Future<int> doAsyncThing() => new Future.value(42);
usingAsync() async => doAsyncThing();
main() {
var thing = usingAsync();
// what is the runtimeType of thing ?
}
What is the runtimeType of the object returned by usingAsync() ? Would it be Future<Future<int>> or Future<int> or something else ?
The return type of usingAsync() is technically dynamic because there is no return type annotation given for usingAsync(). Omitting a return type annotation is the same as using dynamic for the return type annotation.
The runtimeType of the object returned by usingAsync() is Future<dynamic>. Functions marked with async simply always return a Future<dynamic> object.
When the Future from usingAsync() completes, it "flattens" its contained Future, and completes with an int.
import 'dart:async';
Future<int> doAsyncThing() => new Future.value(42);
usingAsync() async => doAsyncThing();
main() {
var thing = usingAsync();
// what is the runtimeType of thing ?
print(thing.runtimeType); // Future
thing.then((value) {
print(value); // 42
print(value.runtimeType); // int
});
}
The author of the code sample in the original question probably wants to write:
Future<int> usingAsync() async => await doAsyncThing();
Or, even cleaner:
Future<int> usingAsync() => doAsyncThing();
That is, if your function returns a Future, you might not need to mark your function as async. Just return the Future.
See it in action: https://dartpad.dartlang.org/73fed0857efab196e3f9