I use retrofit2 in my project. I have interface:
public interface ProductService {
#POST("findProducts")
Observable<ProductsResponse> getProducts();
}
and service method:
public ProductService getProductService() {
return getService(ProductService.class);
}
After that I use this service in my fragment. When I click to button I call this method:
#Override
public void onClick(View view) {
if (view.getId() == R.id.button) {
RestApiFactory.getInstance().getProductService().getProducts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new ProductHandler());
}
}
and realise handler in this fragment:
private class ProductHandler implements Observer<ProductsResponse> {
#Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe: start");
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void onNext(ProductsResponse value) {
//save to DB in new Thread
}
#Override
public void onError(Throwable e) {
Log.d(TAG, "onError: "+ e.getMessage());
price.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.INVISIBLE);
}
#Override
public void onComplete() {
Log.d(TAG, "onComplete: finish");
price.setVisibility(View.INVISIBLE);
progressBar.setVisibility(View.INVISIBLE);
}
}
is it correct to implement ProductHandler implements Observer<ProductsResponse>'s methods
onSubscribe
onNext
onError
onComplete
in fragment?
I'm advised to move this in a singleton:
MySingleton.getInstanse().getData();
and move all to getData :
public void getData(){
RestApiFactory.getInstance().getProductService().getProducts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ProductsResponse>() {
#Override
public void onSubscribe(Disposable d) {
//send broadcast and catch in Fragment
}
#Override
public void onNext(ProductsResponse productsResponse) {
//send broadcast and catch in Fragment
}
#Override
public void onError(Throwable e) {
//send broadcast and catch in Fragment
}
#Override
public void onComplete() {
//send broadcast and catch in Fragment
}
});
}
but I think this is nonsense. who will tell you how to use it (in what place) Observable from retrofit?
there is no need to implement Observer.You can just need to create an observer for the same.Let's see the example.
service.getProducts()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(mObserver);
}
the observer should look like and must be initialized in oncreate:
mObserver = new Observer<ProductsResponse>() {
#Override
public void onSubscribe(Disposable d) {
mDisposableList.add(d);
}
#Override
public void onNext(ProductsResponse value) {
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
}
};
Related
I need help for RxJava. Everything is working fine. But I want to call onNext manually in my other method.
Observable<Data> mylist = Observable.fromIterable(datalist);
mylist.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.buffer(6)
.subscribe(new Observer<List<Data>>() {
#Override
public void onSubscribe(Disposable d) { }
#Override
public void onNext(List<Data> list) {
myadapter.addData(list);
}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() { fetchNextPage(); }
});
Like this:
OnloadMore() {
onNext()
}
I make n asynchronous calls (n being the size of the arraylist, and indexes passed as integer parameters to the calls) and want to invoke a method when all of the calls are completed. I implemented the following code below. I used a counter to know that all of the calls are completed. It is working, however I know that it could be done in a more efficient and elegant way.
int n = mUserUrls.getM3u().size();
counter = n;
Observable.range(0, n)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Integer>() {
#Override
public void accept(Integer integer) throws Exception {
final int index = integer;
Single<ResponseBody> singleGetChannels = aPI.getChannels(mUserUrls.getM3u().get(integer))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Single<List<EPG>> singleGetEPGs = aPI.getEPGs(mUserUrls.getJson())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Single.zip(singleGetChannels, singleGetEPGs, new BiFunction<ResponseBody, List<EPG>, ChannelsAndEPG>() {
#Override
public ChannelsAndEPG apply(ResponseBody responseBodyChannels, List<EPG> ePGs) {
ChannelsAndEPG channelsAndEPG = new ChannelsAndEPG(responseBodyChannels, ePGs);
return channelsAndEPG;
}
}).subscribe(new SingleObserver<ChannelsAndEPG>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(ChannelsAndEPG channelsAndEPG) {
m3Us.put(index, M3UParser.parseList(channelsAndEPG.mResponseBodyChannels.byteStream()));
setEPGs(index, channelsAndEPG.mEPG);
setEPGsForNext24Hours();
counter--;
if (counter == 0) {
if (mCallback != null) {
isDataLoaded = true;
mCallback.onDataLoaded();
}
}
}
#Override
public void onError(Throwable e) {
}
});
}
})
.subscribe(new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Integer integer) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.i(TAG, "onComplete called");
}
});
You can use flatMap to convert each integer to Single ( same way you're doing it now). And then call toList to get Single.
You could use this :
Observable.fromIterable(mUserUrls.getM3u())
.flatMap{ m3u ->
aPI.getChannels(m3u.getInteger)
.zipWith(aPI.getEPGs(mUserUrls.getJson()))
.subscribeOn(Schedulers.io())
}
.doOnNext{
m3Us.put(index, M3UParser.parseList(channelsAndEPG.mResponseBodyChannels.byteStream()));
setEPGs(index, channelsAndEPG.mEPG);
setEPGsForNext24Hours();
}
.subscribe(new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Integer integer) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.i(TAG, "onComplete called");
}
})
I have a problem with retrofit and rxjava
my code below :
#GET(ApiAddress.LANGUAGE_ALL)
Single<Response<Language>> languageAll();
and implements it :
apiRepository.languageAll().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SubscribeWithView<Response<Language>>(view) {
#Override
public void onSuccess(Response<Language> response) {
if (response.isSuccess()) {
view.setLanguage(response.getData().getResults());
}
}
#Override
public void onError(Throwable e) {
super.onError(e);
}
});
and my SubscribeWithView below:
public abstract class SubscribeWithView<T> implements SingleObserver<T> {
private WeakReference<RootView> rootView;
public SubscribeWithView(RootView rootView) {
this.rootView = new WeakReference<>(rootView);
}
#Override
public void onSubscribe(Disposable d) {
if (rootView.get() != null)
rootView.get().addDisposable(d);
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
if (rootView.get() != null)
rootView.get().onError(e);
}
}
why onSubscribe(Disposable d) : d always null ???
If you get a null value error after closing fragment or activity, this means your observable is still alive. For that you should unsubscribe your fragment in onPause() or onStop() or onDestroy(). For example :
Disposable disposable = callApiWithRetrofit().subscribeOn(Schedulers.io()).observeOn(
AndroidSchedulers.mainThread()).subscribeWith(
new DisposableObserver<List<YourPojo>>() {
#Override
protected void onStart() {
super.onStart();
}
#Override
public void onNext(#NonNull List<AlertAssetDTO> listResponse) {
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});
#Override
protected void onDestroy() {
super.onStop();
disposable.dispose();
}
I created an Observable using the Observable.fromCallable method and subscribed to it as shown in the code snippet below.
Observable<String> stringObservable = Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
Thread.sleep(1000);
return Thread.currentThread().getName();
}
});
stringObservable.subscribeOn(Schedulers.io());
stringObservable.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String aDouble) {
Toast.makeText(SimpleActivity.this, "onNext: " + aDouble,
Toast.LENGTH_LONG).show();
}
#Override
public void onError(Throwable e) {
new AlertDialog.Builder(SimpleActivity.this)
.setTitle("Error")
.setMessage(e.toString())
.show();
}
#Override
public void onComplete() {
}
});
The snippet above produced a toast showing that the Callable was run on the main thread instead of the Schedulers.io thread. What's happening?
Every operation on an Observable creates a new instance and does not effect the original one. Therefore
stringObservable.subscribeOn(Schedulers.io());
does not affect your code below.
The correct way of using them would be in a chain instead of using a variable.
Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
Thread.sleep(1000);
return Thread.currentThread().getName();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String aDouble) {
Toast.makeText(SimpleActivity.this, "onNext: " + aDouble,
Toast.LENGTH_LONG).show();
}
#Override
public void onError(Throwable e) {
new AlertDialog.Builder(SimpleActivity.this)
.setTitle("Error")
.setMessage(e.toString())
.show();
}
#Override
public void onComplete() {
}
});
Am doing a weather API call every 3secs and append the result to a textView using showWeather("weather") but I am sure there is a better way to do it. Am not sure why I need create Class Func1 but did because map required it. Also is there a way to shorten observer? I don't use lamda unfortunately. Any suggestions?
Observer myObserver = new Observer<String>() {
#Override
public void onError(Throwable e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String value) {
showWeather(value);
}
};
class Func1<T, T1> implements io.reactivex.functions.Function<Long, String > {
#Override
public String apply(Long aLong) throws Exception {
return getJSON("http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b1b15e88fa797225412429c1c50c122a1",300);
}
}
Observable.interval(3, TimeUnit.SECONDS)
.map(new Func1<Long, Observable<String>>() {
}).observeOn(AndroidSchedulers.mainThread()).subscribe(myObserver);
I tried :
Observable
.interval(3, SECONDS)
.subscribeOn(Schedulers.io())
.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
return getJSON("http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b1b15e88fa797225412429c1c50c122a1", 300);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(myObserver)
But I get :
03-07 21:47:25.982 21181-21181/com.alex.rxandroidexamples E/imerExampleFragment$1$1: null
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1273)
Also how do I unsubscribe onPause or onPause?
I found out the best way to do this is :
private final CompositeDisposable disposables = new CompositeDisposable();
Observable fetchWeatherInterval = Observable.interval(3, TimeUnit.SECONDS)
.map(new Function<Long, String>() {
#Override
public String apply(Long aLong) throws Exception {
return getWeather("http://samples.openweathermap.org/data/2.5/weather?", "London,uk", "b1b15e88fa797225412429c1c50c122a1");
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
Observer displayWeatherInterval = new Observer<String>() {
#Override
public void onError(Throwable e) {
Log.e("Throwable ERROR", e.getMessage());
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
disposables.add(d);
}
#Override
public void onNext(String value) {
textViewWeatherInterval.append(value);
}
};
buttonFetchIntervalWeather.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fetchWeatherInterval.subscribe(displayWeatherInterval);
}
});