How take process multithreaded load for the item list. I get from api list string elements. Next need to get data for items this list. Load need to use rxjava. Result need do getting to the single subscribe.
Next need to get data for items this list
What it has to be? Just method inside your class or separate network request for each of strings?
For first case:
getListFromApi()
.toFlowable()
.flatMap { Flowable.fromIterable(it) }
.map { getSomeData(it) }
.toList()
.subscribe()
Second case:
getListFromApi()
.toFlowable()
.flatMap { Flowable.fromIterable(it) }
.map { requestForSomeData(it) }
.toList()
.flatMap { flowablesList -> Single.zip(flowablesList.map { it.firstOrError() }) { it.toList() } }
.subscribe()
Related
So I have a function which is placing a call using RxJava and then this function is supposed to insert the element returned into a list.
So the code works fine. I am able to retrieve and all items in the cart list. However if an error code generated by the getItem appears (getItem place an API call) such 401 or 404..., I want to continue in the iteration and just bypass the insert. I can't use onErrorReturnItem with a null and filter on null after.
return Observable.just(itemResponses)
.flatMapIterable { it }
.flatMapSingle { itemResponse ->
itemWarehouse.getItem(itemResponse.id)
.map { item ->
itemData(
itemResponse.id,
item,
itemResponse.info,
false,
itemResponse.result)
}
}
.map { itemData -> cartMap[itemData.id]?.insert(itemData) }
.toList()
.map { cartMap.values.toList() }
}
Any idea ?
This should work
return Observable.just(itemResponses)
.flatMapIterable { it }
.flatMap { itemResponse ->
itemWarehouse.getItem(itemResponse.id)
.toObservable()
.map { item ->
itemData(
itemResponse.id,
item,
itemResponse.info,
false,
itemResponse.result)
}
.onErrorResumeNext(Observable.empty())
}
.map { itemData -> cartMap[itemData.id]?.insert(itemData) }
.toList()
.map { cartMap.values.toList() }
I am using RxJava to get list of Posts from JSONplaceholder api.
https://jsonplaceholder.typicode.com/posts
I want to take only the top 10 from the list and save in the data base.
I am aware I need to use take operator but cannot figure out how to use that with concatMap.
Here is what I have already.
private fun loadPosts(){
subscription = Observable.fromCallable { postDao.all }
.concatMap { dbPostList ->
postApi.getPosts().concatMap { apiPostList ->
//HERE i ONLY WANT TO TAKE 10 ITEMS AND SAVE IT (HOW CAN I USE TAKE OPERATOR HERE)
postDao.insertAll(*apiPostList.toTypedArray())
Observable.just(apiPostList)
}
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { onRetrievePostListStart() }
.doOnTerminate { onRetrievePostListFinish() }
.subscribe(
{ result -> onRetrievePostListSuccess(result) },
{ onRetrievePostListError() }
)
}
Below code I tried and it does not work as expected.
postApi.getPosts()
.take(10) // DOES NOT WORK
.concatMap { apiPostList ->
postDao.insertAll(*apiPostList.toTypedArray())
Observable.just(apiPostList)
}
getPosts() returns a list. To use take(10) in your case you'd have to emit each element of the list individual. However, since you emit the entire list in one go, it is as if take(10) is trying to take 10 lists of posts rather than 10 posts.
I can think of 2 ways to fix this. You can convert the list to and observable like:
postApi.getPosts()
.flatMap { Observable.fromIterable(it) }
.take(10)
.toList()
Emit each item of the list, take 10 of them and collect the results in a list ready for your concatMap.
Another option is to manually slice the list:
postApi.getPosts()
.map { it.slice(0 until 10) }
Not so rx-ish but still should work.
Careful because both approaches assume there are at least 10 items in the list.
This is what I want:
Check if I have data about products in database.
If I have data I run Single to get data from DB.
If not I run Single for get data from backend
If I get response I want to save data in DB using Completable.
After saving data I want to map values from step 2 or 3 to view model
In result I want to send data to activity.
This is what I have now:
checkProductsInDBUseCase.run()
.flatMap {
if (it) {
getProductsFromDBUseCase.run()
} else {
getProductsUseCase.run(3)
}
}.map {
it.products.map { item -> item.toViewModel() }
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = {
view.showBikes(it)
},
onError = {
view.showBikesError(it.message.toString())
}
).addTo(disposables)
Between flat map and map I need to run saveDataUseCase(it), but I don't know how to pass itfrom completable to map. Any ideas?
If your saveDataUseCase() is Completable then you can do this
checkProductsInDBUseCase.run()
.flatMap {
if (it) {
getProductsFromDBUseCase.run()
} else {
getProductsUseCase.run(3)
}
}
.faltMap {
saveDataUseCase(it).toSingleDefault(it)
}
.map {
it.products.map { item -> item.toViewModel() }
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = {
view.showBikes(it)
},
onError = {
view.showBikesError(it.message.toString())
}
).addTo(disposables)
But if you change return type of saveDataUseCase() to Unit, you can use Fred's answer. It would be better
Here I'd use doOnSuccess. This seems ideal especially because you're creating a side effect, which we usually use the doOnXXX methods for.
checkProductsInDBUseCase.run()
.flatMap {
if (it) {
getProductsFromDBUseCase.run()
} else {
getProductsUseCase.run(3)
}
}
.doOnSuccess {
saveDataUseCase(it)
}
.map {
it.products.map { item -> item.toViewModel() }
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onSuccess = {
view.showBikes(it)
},
onError = {
view.showBikesError(it.message.toString())
}
).addTo(disposables)
The method will not change the result of the flatMap so you will still get the correct object inside the map function.
I have a method that does a call to Firebase. This method accepts a date and returns an observable.
Then I have an array of dates, that will be used as parameter of this firebase call.
I need to call the method once per item in the array, and finally concatenate to a one list.
But I don't know how to achieve it.
I'm trying to do something like:
for (dateToRetrieve in listOfDatesToRetrieve) {
val subscription = FireBaseUtils.getEventsForMap(dateToRetrieve)
.subscribeOn(Schedulers.io())
.subscribe { retrievedEventsForMap ->
val eventsList: MutableList<Event> = retrievedEventsForMap
eventListWithNoDuplicatesTotal.addAll(eventsList)
var eventListWithNoDuplicates = eventListWithNoDuplicatesTotal.distinctBy { it -> it.eventID }
this.presenter.onEventsRetrieved(eventListWithNoDuplicates as MutableList<Event>)
}
this.presenter.addSubscription(subscription)
}
But I know that is not the best solution because I'm sending the calls one by one, and adding to the list.
Is there any possibility to do it and return 1 result with the combination of all the calls?
Thanks
Try this:
val subscription = Observable.fromIterable(listOfDatesToRetrieve)
.flatMap(dateToRetrieve -> FireBaseUtils.getEventsForMap(dateToRetrieve))
.flatMapIterable { item -> item }
.toList()
.distinct { it -> it.eventID }
.subscribeOn(Schedulers.io())
.subscribe { list ->
this.presenter.onEventsRetrieved(list as MutableList<Event>)
}
this.presenter.addSubscription(subscription)
I want to convert every object in my list to an another object. But in doing so my code stucks in converting them back to List
override fun myFunction(): LiveData<MutableList<MyModel>> {
return mySdk
.getAllElements() // Returns Flowable<List<CustomObject>>
.flatMap { Flowable.fromIterable(it) }
.map {MyModel(it.name!!, it.phoneNumber!!) }
.toList() //Debugger does not enter here
.toFlowable()
.onErrorReturn { Collections.emptyList() }
.subscribeOn(Schedulers.io())
.to { LiveDataReactiveStreams.fromPublisher(it) }
}
Everything is fine until mapping. But debugger does not even stop at toList or any other below toList. How can I solve this?
Using flatMap() you'll only flatten the Flowable of lists to a single Flowable of the elements. Calling toList() on it requires the Flowable to complete and therefore you'll most likely never get there. If you only want to map the elements in the list and have an item with the new list emitted, you should do the mapping within flatMap() or maybe try using concatMap() to keep the order:
...
.concatMapSingle { list ->
Observable.fromIterable(list).map {
MyModel(it.name!!, it.phoneNumber!!)
}.toList()
}
...
Here is my solution to this. Thanks to Tim for leading me to right answer.
override fun myFunction(): LiveData<MutableList<MyModel>> {
return mySdk
.getAllElements() // Returns Flowable<List<CustomObject>>
.flatMapSingle { Observable.fromIterable(it).map { MyModel(it.name!!, it.phoneNumber!!) }.toList() }
.toFlowable()
.onErrorReturn { Collections.emptyList() }
.subscribeOn(Schedulers.io())
.to { LiveDataReactiveStreams.fromPublisher(it) }
}