private Observable< SimpleResource > resource;
return resource.map(new Function<SimpleResource, Flowable<Data>>() {
#Override
public Flowable< Data > apply(SimpleResource resource) throws Exception {
return resource.data().toFlowable();
}
});
Single<Data> data();
I need to have Flowable but my result is Observable>
Since you mentioned that data() returns a Single, you need to transform all of the single streams into one large stream. To transform streams into streams, we generally use the flatmap operator:
resource.flatMapSingle(
new Function<SimpleResource, Single<Data>>() {
#Override
public Single<Data> apply(SimpleResource resource) throws Exception {
return resource.data();
}
}
).toFlowable(BackpressureStrategy.BUFFER);
What you are doing wrong is applying .toFlowable at not the right spot.
Observable.fromCallable { 1 }.map {
it * 2
}.toFlowable(BackpressureStrategy.BUFFER)
If you have different data type returned by data (sorry for Kotlin, but the concept is the same)
data class A(
val data: Single<Int>
) {
constructor() : this(data = Single.fromCallable { 1 })
}
val result: Flowable<Int> = Flowable
.fromCallable {
A()
}
.flatMap {
it.data.toFlowable()
}
Related
I have an object
data class Question(
var publishDate: DateTime?,
var tags: List<QuestionTags>
etc.
Now it's sorted by publishDate
val sortedQuestions = questions.sortedBy { it.publishDate }
But I would like to sort it by one of its tags chapterId. QuestionTags looks like this
data class QuestionTags(
val id: Long,
val chapterId: Long?
etc.
I was trying to do some RxJava magic
sortedQuestions =
questions.flatMap { it.tags }
.filter { it.chapterId != null }
.map { sortedQuestions[0] }
.sortedBy { it.blablabla }
But it isn't working in any case.
How to .map it or .flatMap it to make it happen?
I was trying to flatMap it to QuestionTags, than map it to Question
sortedQuestions =
questions.flatMap { it.tags }
.filter { it.chapterId != null }
.map { Question() }
But in .map { Question() } it force me to pass values to all constructor parameters, which I don't want to do.
It should be sorted by first chapterId from list. And if both have same chapterId, they should be sorted by publishDate, like it's already done
Then you don't need flatMap (or RxJava) at all:
questions.sortedBy { Pair(it.tags.firstOrNull(), it.publishDate) }
I want to call several api and combine the response values of different object types.
val itemList : MutableList<BaseItem>
private fun fetchAllData() {
viewModelScope.launch{
val deferreds = listOf(
async { loadData1()},
async { loadData2()}
)
deferreds.awaitAll().forEach {
itemList.add(it)
}
}
}
I want to get a return by combining datatype1 and datatype2 into BaseItem.
Unable to return the callback data from the repository.
I think there's a way to do it using live data. What should I do?
fun loadData1(): ArrayList<DataType1> {
repository.getData1(param, callback) {
onSuccess(List<DataType1>) {
return
}
}
}
fun loadData2(): ArrayList<DataType2> {
repository.getData1(param, callback) {
onSuccess(List<DataType2>) {
return
}
}
}
I'll be waiting for your help.
Well, what I would do is I would switch repository functions to be suspend functions and write the code in synchronized way:
val itemsLiveData = MutableLiveData<BaseItem>()
private fun fetchAllData() = viewModelScope.launch{
try {
val itemList : MutableList<BaseItem>
itemsList.addAll(repository.loadData1(param))
itemsList.addAll(repository.loadData2(param))
itemsLiveData.postValue(itemsList)
} catch(e: Exception) {
// do something with exception
}
}
And if you want to call several Rest API for example, I would go with Retrofit which has built-in support for suspend functions since ver. 2.6.0
https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05
I have a service like this
#GET("/")
fun getInfo(#Query("pew") pew1: Double, #Query("pew2") pew2: Double): Observable<PewResponse>
So now, when I have this
I have a List to fill with server data
private var mPewList: MutableList<PewList> = arrayListOf()
And then I have this function
override fun getResultFromNetwork(): Observable<PewResponse> {
val pewObservable = pewService.getInfo("pew1","pew2")
return pewObservable.concatMap {
//How do I fill my list ??
}
}
I'm pretty new to this rxJava so I saw people using Single and other guys using Observable what's better?
EDIT
I'm following this example https://github.com/joanby/android-mvp/blob/master/MoviesFeed/app/src/main/java/com/juangabriel/moviesfeed/movies/MoviesRepository.java
And now I want to do something like this :
#Override
public Observable<Result> getResultFromNetwork() {
Observable<TopMoviesRated> topMoviesRatedObservable = moviesApiService.getTopMoviesRated(1)
/*.concatWith(moviesApiService.getTopMoviesRated(2))
.concatWith(moviesApiService.getTopMoviesRated(3))*/;
return topMoviesRatedObservable
.concatMap(new Function<TopMoviesRated, Observable<Result>>() {
#Override
public Observable<Result> apply(TopMoviesRated topMoviesRated) {
return Observable.fromIterable(topMoviesRated.getResults());
}
}).doOnNext(new Consumer<Result>() {
#Override
public void accept(Result result) {
results.add(result);
}
});
}
So as I'm seeing he fills the result list, and then on presenter do this : https://github.com/joanby/android-mvp/blob/master/MoviesFeed/app/src/main/java/com/juangabriel/moviesfeed/movies/MoviesPresenter.java
If your data from server is monolithic you should to use Single because it return only once value. The Observable will do when your data arrives in chunks.
For more details you can see this answer: https://stackoverflow.com/a/42759432/9060113
EDIT:
#GET("/")
fun getInfo(#Query("pew") pew1: Double, #Query("pew2") pew2: Double): Single<PewResponse>
override fun getResultFromNetwork() {
pewService
.getInfo("pew1","pew2")
.subscribeOn(Schedulers.io()) // for background processing
.observeOn(AndroidSchedulers.mainThread()) // get result in Main Thread (it require rxAndroid lib)
.subscribe(
{ pewResponse -> // parse response and fill list },
{ // handle error }
)
}
A RESTful API End-point returns a JSON Response.
The JSON Response consists of 20 different JSON-Array elements. Each element has a Image URL.
After receiving the first response, I intend to loop through the JSON-Array and fetch the images as well, using Retrofit Dynamic URLs.
class Content { var items List<Item>? = null }
class Item { var image: String? = null
var imageBytes: ByteArray? = null
}
interface RestApi { #GET fun getContent(): Single<Content>
#GET fun getImageBytes(#Url url: String): Single<ResponseBody>
}
restApi.getContent()
.map { content: Content -> {
content.items?.forEach { item ->
restApi.getImageBytes(item.image)
.subscribe(object : DisposableSingleObserver<ResponseBody>() {
onSuccess(body: ResponseBody) {
item.imageBytes = body.getBytes()
}
onError(e: Throwable) { // TODO Implementation }
})
}
}
}
How do I make the getContent() method delay before emitting until all invocations of the getImageBytes() also complete with either success or error?
With Single you should use flatten observable it will give a list of observables which the flat map will take up
getListOfItems()
.flattenAsObservable(new Function<Object, Iterable<?>>() {
#Override
public Iterable<?> apply(#NonNull Object o) throws Exception {
return toItems(o);
}
})
.flatMap(item -> doSomethingWithItem())
.toList()
Trying to test new Android Room librarty with RxJava adapter. And I want to handle result if my query returns 0 objects from DB:
So here is DAO method:
#Query("SELECT * FROM auth_info")
fun getAuthInfo(): Flowable<AuthResponse>
And how I handle it:
database.authDao()
.getAuthInfo()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.switchIfEmpty { Log.d(TAG, "IS EMPTY") }
.firstOrError()
.subscribe(
{ authResponse -> Log.d(TAG, authResponse.token) },
{ error -> Log.d(TAG, error.message) })
My DB is empty, so I expect .switchIfEmty() to work, but none of handling methods is firing. Neither .subscribe() nor .switchIfEmpty()
Db Flowables are observable (so they keep dispatching if database changes) so it never completes. You can try returning List<AuthResponse>. We've considered back porting an optional but decided not to do it, at least for now. Instead, we'll probably add support for Optional in different known libraries.
In version 1.0.0-alpha5, room added support of Maybe and Single to DAOs, so now you can write something like
#Query("SELECT * FROM auth_info")
fun getAuthInfo(): Maybe<AuthResponse>
You can read more about it here
switchIfEmpty takes as parameter a Publisher<AuthResponse>. Through SAM-conversion your given anonymous function is turned into this class. However it does not follow the behavior expected from a Publisher so it will not work as expected.
Replace it with a correct implementation like Flowable.empty().doOnSubscribe { Log.d(TAG, "IS EMPTY") } and it should work.
You could use some wrapper for result. For example:
public Single<QueryResult<Transaction>> getTransaction(long id) {
return createSingle(() -> database.getTransactionDao().getTransaction(id))
.map(QueryResult::new);
}
public class QueryResult<D> {
public D data;
public QueryResult() {}
public QueryResult(D data) {
this.data = data;
}
public boolean isEmpty(){
return data != null;
}
}
protected <T> Single<T> createSingle(final Callable<T> func) {
return Single.create(emitter -> {
try {
T result = func.call();
emitter.onSuccess(result);
} catch (Exception ex) {
Log.e("TAG", "Error of operation with db");
}
});
}
And use it like 'Single' in this case you will get result in any case. Use:
dbStorage.getTransaction(selectedCoin.getId())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(r -> {
if(!r.isEmpty()){
// we have some data from DB
} else {
}
})