Download multiple content asynchronously from a single coroutine - kotlin-coroutines

Is it possible to download multiple content asynchronously using only a single coroutine? For example, I have an array of urls but I only can obtain this array from within a coroutine. Once I have the array, I would like to download the content for each url in the array but where all of them are done asynchronously:
withContext(appDispatchers.IO) {
val Urls = getUrlsFromBackend()
// Download the content for each url asynchronously
}

You can create child coroutines. Each coroutine is a unit of concurrency, so you create one for each url.
withContext(appDispatchers.IO) {
val Urls = getUrlsFromBackend()
// Download the content for each url asynchronously
val contents = Urls.map{ async { dowloadContent(it) } }.awaitAll()
// Use contents
}

Related

how use coroutine to remodel / replace the callback implementation

Trying to replace the using callback with coroutines. Having a implementation using callback and not sure what is the right approach if coroutines could help.
This is the implementation with callback.
It has a class repository to provide data from either local database or network remote.
class Repository() {
var callback = //callback is provided by the caller
var isReady = false
var data = null
var firstimeCall = true //only need to get from database at first time call
fun getData(cb: ICallback) {
callback = cb
isReady = false
if (firstimeCall) {
firstimeCall = false
data = doGetDataFromDatabase() //sync call to get data from database
isReady = true
callback.onComplete(this)
}
isReady = false
data = doGetDataFromNetwork() {// async call and lamda as the callback
isReady = true
saveToDatabase(data)
callback.onComplete(this)
}
}
}
the repository.getData() could be called multiple times, only first time it will return the data from database first, then
getting from network and saving, then call callback.onComplete() to return the data.
Any other time, it will only do getting from network/save/return data through the callback.
the use case are:
directly using Repository, like
repository.getData() -- 1st time call
repository.getData() -- later call it again
there are multiple repositories, the data from each one will be aggregated into a final data.
for this case there is a Aggregator to hold the repositories, and provides onComplete() callback to process data if all
repositories are ready.
class Aggregator {
var repos = ArrayList<Repository>()
fun getData() {
for (r in repos) {
Thread {
r.getData(callback)
}.start()
}
}
fun processData(data: ArrayList()) {
......
}
val callback = object ICallback (onComplete{repo->
val hasAllComplete = repos.all {
it.isReady
}
if (hasAllComplete) {
var finalData = ArrayList<Data>()
for (r in repos) {
finalData.add(r.data)
}
processData(finalData)
}
})
}
so in the case it has two Repository, the Aggregator.getData() will get data from the two repositories.
when one Repository is complete its getData() call, it will callback to the callback's onComplete() where
the Aggregator will check wether all repositories are ready for data to be processed.
The same callback flow is used for the network call aswell.
Question:
In this case how to change to use coroutines, so that only after getting data from the database are complete for both repositories,
then it will start to get data from the network, without using callbacks.
I'm not sure if it's relevant anymore, but you could have a look at callbackFlow.
More info here:
https://medium.com/#elizarov/callbacks-and-kotlin-flows-2b53aa2525cf#1aaf
I have a similar problem, and I think this might be the solution to it.
Make sure you also read more about Flow and its usage before actually using it, since there are some caveats with handling exceptions (exception transparency), etc.

How to route ASP.Net Core api return value to appropriate observable based on data type returned

I have created an ASP.NET Core Web Api backend with an Angular 7 frontend. One of the methods in the Api can return either an object or an array to an Angular service. How do I route to specific observable, based on the data type returned? I am a noob to Angular, so any kind assistance would be appreciated.
Angular service call to Api:
getLinksFromSitus(situs: any) {
this.http.post(this.baseUrl + 'getLinksFromSitus', situs).subscribe(data =>
this.apiData.next(data)
);
}
Portion of Web Api that returns array if more than one APN present:
// if more than one item in list, get status information for each and return list to user to select appropriate apn
if (propApn.Count > 1)
{
return Ok(propApn);
}
Portion of same method to return object if only one value for APN:
var resultsModel = new Results
{
ArcGisLink = arcGisLink,
HistInfoLink = histInfoLink,
PropInfoLink = propInfoLink
};
return Ok(resultsModel);
You can't do this. Typescript can only type things based on static analysis at build time, what your describing would require Typescript to know the result of your API call at build time, which it doesn't do.
The best you can do is indicating that your API call can return both of your them:
public myApiFunc(req: MyRequestModel): Observable<any>
But that will still require you to figure out which type returned at runtime.
I was able to find a solution that worked...
getLinksFromSitus(situs: any) {
this.http.post(this.baseUrl + 'getLinksFromSitus', situs).subscribe(data => {
if (data.hasOwnProperty('arcGisLink')) {
this.apiData.next(data);
} else {
let vals = [];
vals = this.apiPropApn.getValue();
const item = vals.concat(data);
this.apiPropApn.next(item);
}
});
}
So, after subscribing to the HttpResponse, I am able to check if the data in the response contains a known property. If it doesn't contain the known property, then it concatenates the data to a BehaviorSubject array. It works perfectly.

Handle data after http get request in angular

I have a service that requests data from a get method, I'd like to map the response to an object storing some Ids and use those Ids to make other http requests.
I was told this isn't usually done in a callback manner, I looked at this How do I return the response from an asynchronous call? but I don't think it's the usual way to implement services, any hints are very appreciated.
Tried adding in onInit/constructor method in angular to be sure the object was filled before other methods were called without success.
#Injectable ()
export class ContactService {
storeIds;
getIds(callback: Function) {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
callback(response);
});
getIds(res => {
this.storeIds = {
profileId: res.profile,
refIds: res.refIds
}
}
)
// this.storeIds returns undefined as it's an async call
this.http.post<any>(WebserviceUrl + this.storeIds.profileId , data, headers )
// .....Many other web services that relay on this Ids
}
Just create another service called StoreIdsService. Update the response you get from your first api call 'getIds' in the StoreIdsService. The idea is to have StoreIdsService as singleton service to keep state of your storeIds. You can inject StoreIdsService in anywhere component you want to get the storeIds.
Its one of manyways to share data in angular between components.
Please refer to this answer someone has posted.
How do I share data between components in Angular 2?
You can simply assign the service response to the storeIds property inside the subscribe method. and call the subsequent services inside it if you need.
#Injectable ()
export class ContactService {
storeIds;
getIds() {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
this.storeIds = {
profileId: response.profile,
refIds: response.refIds
}
this.otherapicall1();
this.otherapicall2();
});
}

Task<String> in Object Cache

I am using this line of code to read previously saved Object from Cache
Task<string> responselist = cache["responselist"] as Task<string>;
Line used to save the object
cache.Set("responselist", response.Content.ReadAsStringAsync(), policy);
The reason I am using responselist variable as type Task because I return "Task" object in my method.
I am fairly new to Web API. I just want to know if it makes sense to this or there's better alternative?
PS: it works 100% fine.
You should use async/await keywords for it and store the primitive types in cache.
public async Task Action(...)
{
string content = await response.Content.ReadAsStringAsync();
cache.Set("responselist", content, policy);
/* ... */
string content = cache["responselist"] as string;
}
Storing the basic types/POCO classes is more natural than class like Task. By using the basic types you can save capacity in cache.

Asynchronous image loading in AS3

I understand that images are to be loaded asynchronously in AS3, and that that synchronisation should be handled using events and event listeners.
So, in a simple case, it would look like this:
var loader : Loader = new Loader();
var im_file: URLRequest = new URLRequest ("imfile.png");
loader.load(im_file);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loading_complete);
function loading_complete (e : Event) : void
{ // ... do smt with your loaded data // }
What I want to do is have a PreLoader class that will load all the images I need beforehand.
In that case, how do I let all the other classes know when the loading is done?
Do I dispatch events? What is the best practise in this case?
Thanks in advance,
Praskaton
Most likely you want to create a queue and add your image paths to the queue. Then after each image is done loading, you proceed to the next item in the queue. When all images are loaded, you dispatch a COMPLETE event or something similar to let your app know it's all done.
Check QueueLoader or Casalib for how they implement single or bulk image loading.
Adding to the answer that #Boon provided, this is how you could go about the actual setting up of the image queue.
Firstly, you need a list that will store all of the images that still need to be loaded. This makes it easy for you to define as many images as you want. It can be the 'queue':
var queue:Array = [
"http://interfacelift.com/wallpaper/previews/03177_orionnebulaintheinfrared#2x.jpg",
"http://interfacelift.com/wallpaper/previews/03175_purpleclouds#2x.jpg",
"http://interfacelift.com/wallpaper/previews/03173_goodmorning2013#2x.jpg"
];
The next thing to do is set up what I would call the 'core' method of what we're doing. It will handle loading the next image as well as notifying us when the queue is empty. It looks something like this:
function loadNext():void
{
if(queue.length > 0)
{
// Notice here that we use .pop() on the queue, which will select and
// remove the last item from queue.
var req:URLRequest = new URLRequest( queue.pop() );
var photo:Loader = new Loader();
photo.load(req);
photo.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
}
else
{
// The queue is finished - dispatch an event or whatever you fancy to
// let the rest of the application know we're done here.
trace("Queue finished.");
}
}
And then of course our listener function to deal with the completion of loaded images. Notice here that we call loadNext() - this is the key to beginning the load of the next image in the queue only once the currently loading image has finished.
function loadComplete(e:Event):void
{
addChild(e.target.content as Bitmap);
// Begin loading next image in the queue.
loadNext();
}
And to start the process we of course just use this, which will either immediately notify us that the queue is finished if it's empty, or start loading the images in sequence.
// Start loading the queue.
loadNext();
Additional / tidy up:
If you want to be able to recycle this code or just tidy up, you can easily make this into a class. The class could be called ImageQueue and its structure will contain the above queue array, loadNext() method and loadComplete() method. It can also have an add() method for adding images to the queue initially in a cleaner manner.
Here is the foundation of that class, which you can finish up if you're interested:
public class ImageQueue
{
private var _queue:Array = [];
public function add(image:String):void{ }
public function loadNext():void{ }
private function _loadComplete(e:Event):void{ }
}

Resources