How to cast/convert Future<dynamic> into Image? - dart

I have function to fetch image like
dynamic imgBinary = _repository.fetchImage(productId);
And I want to add this into List of Image
List<NetworkImage> listImages = new List<NetworkImage>();
So like
dynamic imgBinary = _repository.fetchImage(productId);
listImages.add(imgBinary);
How to cast this?

Ok , So you Can Try .then method.
As _repository.fetchImage(productId); is Future.
so you can try -
List<NetworkImage> listImages = List<NetworkImage>();
Future<dynamic> imgBinary = _repository.fetchImage(productId);
imgBinary.then((i){
listImages.add(i);
});
or
Directly:
_repository.fetchImage(productId).then((i){
listImages.add(i);});
To get the Value from Future - we can either use :
async and await
OR
you can use the then() method to register a callback. This callback fires when the Future completes.
For more info

EDIT: anmol.majhail's answer is better
Your fetchImage method needs to return a future, here's some pseudo code as guidence
List<NetworkImage> listImages = new List<NetworkImage>();
Future<void> _fetchAddImageToList(int productId) async {
//trycatch
dynamic imgBinary = await _repository.fetchImage(productId);
listImages.add(imgBinary);
}
Future<NetworkImage> fetchImage(int id) async {
New NetworkImage img = new NetworkImage();
//do your fetch work here
return img;
}

Related

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;
}

How to complete a Future?

I am searching for something like the following, where I return an object from a method, which can be awaited, and completed from its origin function:
Future<dynamic> customFunction() {
// The following class does not exist, but I am searching for a class that would fill that gap.
FutureWithCompletion future = FutureWithCompletion();
() async { // A callback that represents the usecase.
// some computation
future.completeWith('something');
}
return future;
}
/// This function accesses [customFunction].
/// It should print out "something" once the computation is done.
anotherFunction() async => print(await customFunction());
You need to use a Completer:
Future<String> method() {
final completer = Completer<String>();
Timer(Duration(seconds: 5), () => completer.complete('result'));
return completer.future;
}
return Future.value('something`);
otherwise use a Completer https://api.dartlang.org/stable/2.0.0/dart-async/Completer-class.html

returning a value in sync and await in dart

I am trying to understand the usage of async and await in Dart. Somehow I am having issues returning values in certain methods.
Consider the code below
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
DataSnapshot ss;
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
ss = event.snapshot;
return ss.val();
});
//return Future<int> ss.val();
}
mrn is of type int which should be returned by getMrn method. However each time the returned ss.val() returns null. It seems that ss = event.snapshot is not seen in the last returned value
What is the correct way of doing this.
Thanks
In the code above, you're declaring anonymous function (event){..} as a callback, and your return statement relates to it, while your intention was to return from getMrn().
What are you actually need, is to complete a Future you're returning from getMrn() inside your callback.
Like this:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Completer<int> c = new Completer<int>();
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
DataSnapshot ss = event.snapshot;
c.complete(ss.val());
});
return c.future;
}
but that code wouldn't work good if there second event appear in mrnRef.onValue stream. So, assuming mrnRef.onValue is a Stream, and you need only first event, it would be better to rewrite it this way:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Event event = await mrnRef.onValue.first;
DataSnapshot ss = event.snapshot;
// note, you're implicitly returning a Future<int> here,
// because our function is asyncronous
return ss.val();
}

Future is completed before function-call is done

I'm working with two functions, both of them should return a future. A third function gets called when both of them are done. Right now the future is returned too early, so that my third function is called before my second function is completed.
Function1:
static var getObjectDataCompleter = new Completer();
static var fillObjectCompleter = new Completer();
static Future getObjectData(List jsonMap) {
for (int i = 0; i < jsonMap.length; i++) {
fillObjectCompleter = new Completer();
var request = buildRequest("GET", resourceUrl);
request.send();
request.onLoadEnd.listen((event) => fillObject(request));
}
if(fillObjectCompleter.isCompleted) {
getObjectDataCompleter.complete(null);
}
return getObjectDataCompleter.future;
}
Function2:
static Future fillObject(HttpRequest request) {
String responseText = request.response;
List stringJson = JSON.decode(responseText);
fillObjectCompleter.complete(null);
return fillObjectCompleter.future;
}
Function1 is returning the future before the call "fillObject()" is completed.
What am I doing wrong?
The function1-future should be returned when the "for-loop" is done and all "fillObject-calls" are completed.
Async code is just scheduled for later execution and the sync code continues executing without waiting for the async code. The method you pass ot Future.then(...) is executed when the scheduled async code is finished. You find a lot of such questions and examples tagged [:dart-async:] here on StackOverflow.
I have a hard time figuring out what you actually try to accomplish. Can you please explain in prosa what you actually try to accomplish, then I can try to fix your code example to do what you want it to do.
Usually there is no need to use a Completer in custom async functions. You just have to ensure that nested async calls are properly chained by always returning the future of the call.
See these two lines of the following code as example. The returns are important for the example to work.
return async.Future.forEach(jsonMap, (item) {
return request.onLoadEnd.first.then((event) => fillObject(event.target));
The Future returned from getObjectData completes after the response of all requests are processed.
import 'dart:html' as dom;
import 'dart:async' as async;
import 'dart:convert' show JSON;
class Xxx {
static async.Future getObjectData(List jsonMap) {
return async.Future.forEach(jsonMap, (item) {
//var request = new dom.HttpRequest();
//request.open("GET", "https://www.googleapis.com/discovery/v1/apis?fields=");
var request = buildRequest("GET", resourceUrl);
request.send();
return request.onLoadEnd.first.then((event) => fillObject(event.target));
});
}
static fillObject(dom.HttpRequest request) {
print('fillObject');
String responseText = request.response;
List stringJson = JSON.decode(responseText);
}
}
void main() {
var json = ['a', 'b', 'c'];
Xxx.getObjectData(json).then((_) => print('done'));
}
See https://www.dartlang.org/articles/event-loop for more details about async execution.

Event with return value

I'm using the dart:async library to do some data processing. I'm adding objects to a StreamController and another module is listening to the stream. Now I want, that the other module is returning a result of the processing back to the add call (as a future).
Here is some example code that should illustrate what I want to do (It doesn't work, because the add method doesn't return a future):
final controller = new StreamController();
controller.stream.listen((a) {
// Do something with a, after that return something:
return 42;
});
final aFuture = controller.add(new A());
aFuture.then((result) {
// result == 42
});
Is something like this possible with dart:async, another library, or do I need to write my own classes?
PS: An alternative would be the following, but it would be 'more complicated' to use that a simple return:
final controller = new StreamController();
controller.stream.listen((container) {
// Do something with container.a, after that return something:
container.completer.complete(42);
});
final completer = new Completer();
controller.add(new Container(new A(), completer));
completer.future.then((result) {
// result == 42
});
You could use a wrapper around the StreamController like:
class StreamControllerWrapper{
MessageBox mb;
StreamController controller;
StreamControllerWrapper(this.controller){
mb = new MessageBox();
controller.stream.listen((a) {
var replyTo = a['replyTo'];
// Do something with a, after that return something:
replyTo.add(42);
});
}
Future add(msg){
Completer c = new Completer();
mb.stream.listen((reply){
c.complete(reply);
});
controller.add({'content':msg, 'replyTo':mb.sink});
return c.future;
}
}
And then invoke the behavior like this:
final controllerWrapper = new StreamControllerWrapper(new StreamController());
controllerWrapper.add(new A())
.then((result){
print(result);
});

Resources