I am new in flutter. I need to call 5 API network calls in a single screen. It is taking very long time while i am using Async/await. How can we execute it on separate threads parallelly using isolate or anything else like it?
You may use isolate for this purpose isolate is a sort of multi threading in dart. Isolate creates a new thread and execute operation on the new thread so that the load will be distributed. You cannot send variables as a data back and forth but use port to send messages.
Here is a simple example of isolate with an API call and sending data back to the main thread using port.
First lets create a function which will be the entrypoint of isolate:
static entryPoint(SendPort sendPort)async{
var response = await http.get('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita');
sendPort.send(response.body); //sending data back to main thread's function
}
Now lets create isolate:
static void callApi()async{
var recievePort = new ReceivePort(); //creating new port to listen data
await Isolate.spawn(entryPoint, recievePort.sendPort);//spawing/creating new thread as isolates.
recievePort.listen((message) { //listening data from isolate
print(message);
});
}
You can use dio package and call multiple concurrent API requests, do check the documentation:
Package: https://pub.dev/packages/dio
You can use Future.wait()
Here is the answer with an example
Related
We are using the Azure SignalR service from functions to send messages back to our UI and all is working without issue. But I can't find a definitive answer on how long lived the ServiceManager or HubContext should be.
At the moment each time we want to send a message to the UI we call a class we have written which does the following:
using var serviceManager = return new ServiceManagerBuilder().WithOptions(option =>
{
option.ConnectionString = _connectionString;
option.ServiceTransportType = ServiceTransportType.Persistent;
})
.WithNewtonsoftJson()
.BuildServiceManager();
await using var hubContext = await serviceManager .CreateHubContextAsync(hubName, System.Threading.CancellationToken.None);
await hubContext.Clients.Group(group).SendAsync(method, message);
This all works fine, but we are creating a new ServiceManager and ServiceHubContext every time we send a message.
The samples I have looked at do not include running in functions where we inject a service which handles publishing. Should either of these be Singleton? The functions we have are processing data and sending updates in a loop so we may send 100s of messages in a single function.
I am working on a small flutter app where I use a native library for some computation. The communication is two-way between dart and java (on android) and uses methodChannels for this.
I call await in_channel.invokeMethod("someJavaMethod") from dart to start the computation. This triggers an init of the native library from Java. The result from this init is coming back as an async JNI call which then triggers out_channel.invokeMethod("someDartMethod").
My plan was to bind the out_channel to a local dart broadcast stream such that I could invoke someJavaMethod and then just await myMethodStream.where((m) => m.method == "someDartMethod")...
Problem is that the "someDartMethod" can come before the "someJavaMethod" call invocation has returned.
combined code example of what I have:
static const MethodChannel _channel_in = const
MethodChannel('native_lib_wrapper_out');
static const MethodChannel _channel_out = const
MethodChannel('native_lib_wrapper_in');
final StreamController<MethodCall> _methodStreamController = new
StreamController.broadcast();
NativeLibWrapper._() {
_channel_in.setMethodCallHandler((MethodCall call) {
_methodStreamController.add(call);
return;
});
}
Future<Map<dynamic,dynamic>> initLib(String id, String filePath)
async {
Map<dynamic,dynamic> ret;
ret = await _channel_out.invokeMethod("initLib", <String,
dynamic> { // data to be passed to the function
'id': id,
'filePath': filePath,
});
print('initLib - invokeMethod done. wait for stream');
if(ret["status"] == 0) {
await NativeLibWrapper.instance._methodStream
.where((m) => m.method == "libInitEnded")
.map((m){
var args = m.arguments;
ret = args;
}).first;
}
return ret;
}
I would have expected the code to get the method call libInitEnded on my stream and then it should return after that point but it continuously hangs in the await on the stream and from the logs it looks like the libInitEnded is called before the print in the middle.
So is there a better way to structure this? it will not be the only methods going back and forth so I hope to get a good stable solution for this.
One channel
You should only need one channel. No need for in and out channels. Both ends may invoke operations on the other over the one channel.
There's only one UI thread
When you call from Dart to Native, the native method is handled by the native UI thread. Unless you are using a thread pool, that means that Dart to Native methods are handled in order. There's no point in not awaiting the answer of every native method. Or, in other words, there's no point in launching two native methods at the same time, since they will be executed consecutively by the single native thread. (Note that you should not perform time-consuming operations on the native thread, as this will interfere with other things it does like gesture detection.) Every Dart to native method should return its result.
Using a thread pool
If the single thread / single method call at a time is unacceptable, consider a thread pool at the native end. Now you can have multiple methods in flight, since there are multiple threads of execution. Now you should design your call/response like you might for communication with a server over a socket. The client gives each request an "invoke id". Each method simply returns a boolean that the request was queued. On completion of the request, the other end invokes the 'done' method, passing the original id and the result. The caller can then match up the response id with the request id and handle the response appropriately (and cancel any timer started to detect timeout). Note that responses can then arrive in any order, but are matched with their request by id.
On Android, you must invoke native to Dart methods on the UIThread. If you are calling the 'done' method from a worker thread you need to post a Runnable lambda to the main looper.
What is the recommended way in vert.x to write an Asynchronous request handler?
In this service, a request processing typically involves calling DB, calling external services, etc. I do not want to block the request handling thread however. What is the recommended way to achieve this using vet.x? In a typical asynchronous processing chain, I would use the request handling thread to emit a message to the message bus with the request object. Another handler will pick this message and do some processing such as checking request params. This handler can then emit a new message to the bus which can be picked up by the next handler which will do a remote call. This handler emits a new message with the result of the call which can be picked up by the next handler which will do error checking etc. Next handler would be responsible for creating the response and sending it to the client.
How one can create a similar pipeline using vert.x?
Everything, comprising request handlers for HttpServer, is asynchronous, isn't it?
var server = vertx.createHttpServer(HttpServerOptions())
server.requestHandler { req ->
req.setExpectMultipart(true) // for handling forms
var totalBuffer = Buffer.buffer()
req.handler { buff -> b.appendBuffer(buff) }
.endHandler { // the body has now been fully read
var formAttributes = request.formAttributes()
req.response().putHeader("Content-type","text/html");
req.response().end("Hello HTTP!");
}
// the above is so common that Vertx provides: bodyHandler{totalbuff->..}
}.listen(8080, "127.0.0.1", { res -> if(res.succeeded()) ... });
You just need to (end) write on req.response() on your final handler of your pipeline.
For a more stream-like implementation (i.e., not callback-based), you may use Vert.x Rx/ReactiveStreams API. E.g., you may use Vert.x Web Client for making requests, possibly using its Rx-fied API.
I have a ServiceWorker registered on my page and want to pass some data to it so it can be stored in an IndexedDB and used later for network requests (it's an access token).
Is the correct thing just to use network requests and catch them on the SW side using fetch, or is there something more clever?
Note for future readers wondering similar things to me:
Setting properties on the SW registration object, e.g. setting self.registration.foo to a function within the service worker and doing the following in the page:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
Results in TypeError: reg.foo is not a function. I presume this is something to do with the lifecycle of a ServiceWorker meaning you can't modify it and expect those modification to be accessible in the future, so any interface with a SW likely has to be postMessage style, so perhaps just using fetch is the best way to go...?
So it turns out that you can't actually call a method within a SW from your app (due to lifecycle issues), so you have to use a postMessage API to pass serialized JSON messages around (so no passing callbacks etc).
You can send a message to the controlling SW with the following app code:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
Combined with the following in the SW code:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
Which results in the following in my SW's console:
postMessage received Object {hello: "world"}
So by passing in a message (JS object) which indicates the function and arguments I want to call my event listener can receive it and call the right function in the SW. To return a result to the app code you will need to also pass a port of a MessageChannel in to the SW and then respond via postMessage, for example in the app you'd create and send over a MessageChannel with the data:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(event.data);
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
and then you can respond via it in your Service Worker within the message handler:
evt.ports[0].postMessage({'hello': 'world'});
To pass data to your service worker, the above mentioned is a good way. But in case, if someone is still having a hard time implementing that, there is an other hack around for that,
1 - append your data to get parameter while you load service-worker (for eg., from sw.js -> sw.js?a=x&b=y&c=z)
2- Now in service worker, fetch those data using self.self.location.search.
Note, this will be beneficial only if the data you pass do not change for a particular client very often, other wise it will keep changing the loading url of service worker for that particular client and every time the client reloads or revisits, new service worker is installed.
I am new to Dispatch queue, now am trying to call background operations through this dispatch queue.
Here I have a doubt, please help me in this. In the below example,
whatQueue:- Should it be mainQueue, queueA or shall I create a new Queue?
dispatch_queue_t queueA = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queueA, ^{
NSMutableArray * items = listofItems;
for(NSString * str in items)
{
//Run a sync block to send str to server
dispatch_sync(***whatQueue***, ^{
});
}
});
Thanks,
Phani
You are not explaining too much as to the reasons why you want the inner block to be executed in a sync way. I assume that you want:
to serialize the sending of the strings to the server;
wait for all the strings to be sent before continuing.
In this case, you can:
execute the network task on the same queueA (no need for a new dispatch);
ensure that your underlying networking layer (NSURLConnection/AFNetworking/ASIHTTP/...) is doing a sync network operation (otherwise, the network request will return immediately and complete in the background in its own thread).
Use dispatch_get_main_queue for nested dispatches (I assume you want a sync dispatch on the main thread for UI updates, after all). Otherwise, you're already operating in the background and no further dispatches are required.
thanks for your reply,
I don't want to update any thing on the UI just want push offline data to the server without effecting user interface.
So main dispatch queue iterates all the records and should send records synch mode using nested queue and each request's response should also handled.