How I can use socket.io and rxjava 2 android - android

I develop an app with mpv (mosby3) + socket.io.
I want to use rxjava 2 to relate provider and repository.
I have CategoryManager
public class CategoryManager {
private List<Category> list = null;
...
}
If list not null i can do it
public Single<List<Category>> getList() {
return Single.just(this.list);
}
But if I need load the list I have do it async like a it
socket.on("category", (data) -> {
Type founderListType = new TypeToken<ArrayList<Category>>() {}.getType();
list = gson.fromJson(data[0].toString(), founderListType);
// here i need to generate event to single subscriber
})
I think i should use to
public Single<List<Category>> getList(int count) {
return Single.create(s -> {
if (list == null) {
socket.emit("category");
// i need async load list
} else {
s.onSuccess(list.subList(0, count));
}
});
}
And CategoryPresenter should have code like
disposable.add(session.getCategoryManager()
.getList(5)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
if (isViewAttached()) {
getView().setData(data);
}
}, throwable -> {
throwable.printStackTrace();
})
);
}
I think i can keep subscribers in class property
private List<SingleEmmiter> subscribers;
and remove subscribers in setCancellable method, but i don't think it good idea.
Help me please :)

Related

Get Data from Two api using RxJava

I have two request of api
// to get all products list inside specific category
1. getCategoryProducts : Observable<List<CategoryProductsModel>
class CategoryProductsModel {
int categoryId ;
String sku ;
// sku is variable I used it to get the details for each product (name , images , colors , sizes , price ..etc
}
// to get product details by sku based on first api getCategoryProducts
2.getProductDetails(var sku:String): Observable<ProductDetailsModel>
class ProductDetailsModel {
float price ;
List<Images> images ,
List<Colors> colors ,
etc ...
}
first request is getCategoryProducts then getProductDetails based on the first request to get the sku for each product and pass it to getProductDetails
after I make the second request I want to add the data response in ProductModel to get finally a list of ProductModel to pass it to recycler view
ProductModel
{
CategoryProductsModel mCategoryProductsModel ;
ProductDetailsModel mProductDetailsModel ;
}
I user RxJava to request API. How can I do that?
public void getProductsList() {
getCategoryProductsObservable()
.subscribeOn(Schedulers.io())
.flatMap(new Function<CategoryProductsModel, ObservableSource<List<ProductModel>>>() {
#Override
public ObservableSource<List<ProductModel>> apply(CategoryProductsModel mCategoryProductsModel) throws Exception {
return getProductDetails(mCategoryProductsModel);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(this::fillProducts);
}
public Observable<CategoryProductsModel> getCategoryProductsObservable() {
return Repository.Companion.getStoreInstance().getCategoryProducts(categoryId).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<List<CategoryProductsModel>, ObservableSource<CategoryProductsModel>>() {
#Override
public ObservableSource<CategoryProductsModel> apply(List<CategoryProductsModel> mCategoryProductsList) throws Exception {
return Observable.fromIterable(mCategoryProductsList).subscribeOn(Schedulers.io());
}
}).subscribeOn(Schedulers.io());
}
#SuppressLint("CheckResult")
public Observable<List<ProductModel>> getProductDetails(CategoryProductsModel mCategoryProducts) {
List<ProductModel> mList = new ArrayList<>() ;
return Repository.Companion.getStoreInstance().getProductDetails(mCategoryProducts.getSku())
.map(new Function<ProductDetailsModel, List<ProductModel>>() {
#Override
public List<ProductModel> apply(ProductDetailsModel mProductDetailsModel) throws Exception {
Log.d("mProductDetailsModel", mProductDetailsModel.getName());
ProductModel productModel = new ProductModel() ;
productModel.setProductDetailsModel(mProductDetailsModel);
productModel.setCategoryProductsModel(mCategoryProducts);
mList.add(productModel);
return mList;
}
}).subscribeOn(Schedulers.io());
list of operators you need: switchMap() fromIterable() and toList(). So your code will look like:
getCategoryProductsObservable()
.subscribeOn(Schedulers.io())
.switchMap { listOfProducts -> Observable.fromIterable(listOfProducts)
.map { it.sku }
.flatMap { sku -> getProductDetails(sku) }
.toList()
.map { listOfProductDetails -> /* combine with listOfProducts to Model you need */ }
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::fillProducts);
I used lambdas for shorter answer, can rewrite to Function style, but i guess it's self explanatory.

Best way to get List from Observable in Rxjava

I'm just exploring Rxjava in one of my android application, and got stuck at one place, honestly speaking I'm very new to this library so don't mind if my question frustrate someone;-)
So I'm trying to access the Room Database using RxJava where I'm returning the Observable List, once I get this Observable I'm trying to use map operator to get a list of ids & query again the database, which again returns me the Observable List but the map operator expects List as a return type. How can I tackle this please suggest?
Below is the code snippet:
private void getAllPcbs() {
isLoading.setValue(true);
getCompositeDisposable().add(
getRepositoryManager().loadAllPcbDetails()
.flatMap((Function<List<PcbDetails>, ObservableSource<?>>) pcbDetails -> {
List<Long> pcbList = new ArrayList<>();
for (PcbDetails details : pcbDetails)
pcbList.add(details.getPcbId());
return getRepositoryManager().loadAllPcbs(pcbList);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccess, this::onError)
);
}
private void onError(Throwable throwable) {
isLoading.setValue(false);
}
private void onSuccess(Object o) {
isLoading.setValue(false);
pcbList.setValue((List<Pcb>) o);
}
public interface DbHelper {
Observable<List<PcbDetails>> loadAllPcbDetails();
Observable<List<Pcb>> loadAllPcbs(List<Long> pcbIdList);
}
Go like
getRepositoryManager().loadAllPcbDetails()
.flatMapIterable {
listPcbDetail-> listPcbDetail
// listPcbDetail is ArrayList<PcbDetails>
// Converts your list of ids into an Observable
// which emits every item in the list
}
.flatMap { pcbDetail ->
// pcbDetail is PcbDetails
getRepositoryManager().loadAllPcbs(pcbDetail.pcbIdList)
}.subscribe { listPcb ->
// listPcb is ArrayList<Pcb>
}

"Join" a list of Observables in RxJava

I have been reading the documentation over and over again and I cannot find the right operator for my case:
return Observable.fromIterable(formIds)
.flatMap(new Function<String, Observable<List<Transmission>>>() {
#Override
public Observable<List<Transmission>> apply(String formId) {
return getFormTransmissions(formId);
}
})
.toList()
.toObservable()
.map(new Function<List<List<Transmission>>, List<Transmission>>() {
#Override
public List<Transmission> apply(List<List<Transmission>> lists) {
List<Transmission> transmissions = new ArrayList<>();
for (List<Transmission> transmissionList : lists) {
if (transmissionList != null) {
transmissions.addAll(transmissionList);
}
}
return transmissions;
}
});
As you can see the last map() I take all the observables and combine their content. I don't like this part as I feel there must be some rxjava function to do that but I cannot find one.
I will try to explain what the code does:
From a list of ids
For each one of them, get a list of transmissions for each id
Once all of those complete combine all the individual transmission lists into one. Any ideas?
So basically you need a simple map that can flatten the result. You can do this with flatMapIterable
return Observable.fromIterable(formIds)
.flatMap(new Function<String, Observable<List<Transmission>>>() {
#Override
public Observable<List<Transmission>> apply(String formId) {
return getFormTransmissions(formId);
}
}) // Observable<List<Transmission>>
.flatMapIterable(new Function<List<Transmission>, List<Transmission>>() {
#Override
public List<Transmission> apply(List<Transmission> list) {
return list;
}
}) // Observable<Transmission>
.toList() // Single<List<Transmission>>
.toObservable(); // Observable<List<Transmission>>
Even simpler with Java 8 features:
return Observable.fromIterable(formIds)
.flatMap(formId -> getFormTransmissions(formId)) // Observable<List<Transmission>>
.flatMapIterable(list -> list) // Observable<Transmission>
.toList() // Single<List<Transmission>>
.toObservable(); // Observable<List<Transmission>>
Alternatively you can just use flatMap in Java Stream:
return Observable.fromIterable(formIds)
.flatMap(formId -> getFormTransmissions(formId)) // Observable<List<Transmission>>
.toList() // Single<List<List<Transmission>>>
.toObservable() // Observable<List<List<Transmission>>>
.map(listOfList -> listOfList.stream().flatMap(Collection::stream)
.collect(Collectors.toList())); // Observable<List<Transmission>>

How to Invoke a Method When All of the Parallel HTTP Requests Are Completed?

I need to get the categories, and then get the channels of that categories, and finally invoke a method when all categories and their channels are retrieved from the server. I guess that I need to use RxJava, but I could not find a similar implementation. (Preferably without using lambda/retrolambda expressions).
#GET("/api/{categoryId})
Call<Category> getCategory(#Path("categoryId") String categoryId)
private void getCategories() {
for (Tab t : tabs) {
Call<Category> getCategory = videoAPI.getCategory(t.getId());
getCategory.enqueue(new Callback<Category>() {
#Override
public void onResponse(Call<Category> call, Response<Category> response) {
Category cat = response.body();
categories.add(cat);
// I will call the getChannels(String categoryId) method here,
// however I think implementing RxJava would be much better.
}
#Override
public void onFailure(Call<Category> call, Throwable t) {
Log.i(TAG, "failure: " + t.getLocalizedMessage());
}
});
}
}
You can do that with
Observable
.fromArray(/*your list of observables go here, make sure that within flatMap you get as type Observable<T>, not Observable<List<T>>*/)
.flatMap(/*here you subscribe every item to a different thread, so they're parallel requests: subscribeOn(Schedulers.computation())*/)
.subscribe (/*each request*/,/*error*/,/*completed all requests*/)
Now your request needs to be of type Observable
#GET("/api/{categoryId})
Observable<Category> getCategory(#Path("categoryId") String categoryId)
Example code in Java:
// Setup a list of observables
List<Observable<Category>> parallelRequests = new ArrayList<>();
for (Tab t : tabs) {
parallelRequests.add(videoAPI.getCategory(t.getId()));
}
Observable[] array = new Observable[parallelRequests.size()];
// Convert the list to array
parallelRequests.toArray(array);
Observable
.fromArray(array)
.flatMap(observable -> observable.subscribeOn(Schedulers.computation()))
.subscribe(o -> {
// each request is fulfilled
}, Throwable::printStackTrace, () -> finishFunctionHere());
Or if you're using Kotlin
Observable
// The asterisk is called "spread operator": It converts an array to vararg
.fromArray(*tabs.map { api.getCategory(it.getId()) }.toTypedArray())
.flatMap { it.subscribeOn(Schedulers.computation()) }
.subscribe({ category ->
// onEach
}, Throwable::printStackTrace, {
// All requests were fulfilled
})

RxJava .filter is blocking other code from sending data to API

I'm using RxJava inside an evernote job to send some data to API. This code was working just fine till now. The problem is somewhere in the .filter I think as it isn't even getting to getApiService().createReport(requestModel) method unless there are photos in the model (then the report.getImages() is not null.
public static Observable<Report> createReport(CreateReportModel model) {
return Observable.just(model)
.filter(report -> report.getImages() != null)
.flatMap(report -> {
return Observable.from(report.getImages())
.map(photoModel -> {
return photoModel;
})
.filter(photoModel -> photoModel.hasImage())
.filter(photoModel -> photoModel.getImage().exists())
.flatMap(photoModel -> uploadFile(photoModel)).toList();
})
.map(photoModels -> model)
.flatMap(requestModel -> {
return getApiService().createReport(requestModel)
.map(response -> {
return response;
});
});
}
This function is called inside this code
Observable<PalletReport> report = createReport(model);
report.subscribe(new Subscriber<PalletReport>() {
#Override
public void onCompleted() {
resultHolder.setResult(Result.SUCCESS);
#Override
public void onError(Throwable e) {
Timber.d(e, "Upload Error");
resultHolder.setResult(Result.RESCHEDULE);
}
#Override
public void onNext(PalletReport model) {
Timber.d("On Next " + model);
}
});
And here it goes to Result.SUCCESS but the response isn't get and the report isn't create on back end. My concern is that this code was working just fine a few days ago, and without any changes it stopped.
[EDIT]
I have this function that is called inside the first flatMap, and it's used to send the photos.
#NonNull
private static Observable<? extends CreatePalletPhotoModel> uploadPalletFile(CreatePalletPhotoModel photo) {
MultipartBody.Part fileBody = Paperless.createFileBody(photo.getImage());
return Paperless.getApiService().uploadPalletPhoto(fileBody)
.map(upload -> {
photo.setPalletStatus(upload.getPalletStatus());
photo.setImage(upload.getImage());
return photo;
});
}
If there are no reports after filter nothing will get executed. Consider removing
.map(photoModels -> model)
and just end the first observable there (you would need to subscribe to it) and start again with
Observable.just(model).flatMap(requestModel -> {
return getApiService().createReport(requestModel)
.map(response -> {
return response;
});
});
that will ensure that getApiService call is always executed.

Categories

Resources