Android RxJava: I am not unsubscribing after onComplete - android

I have a class called PendingRequests. This class is basically a counter for Volley Requests. I have two Volley methods - One called CheckOpen and one called CheckCompleted. Each methods selects either Open or Completed records on my SQLite tablet database and checks them against the server.
In CheckOpen and CheckClose, I use three calls to PendingRequests. At the start I call Initialize(), then as I add a volley request to the queue I call Add() and then as I begin to receive responses I call Subtract(). For both CheckOpen or CheckClose I will very quickly Add() up to 50 and then slowly countdown (Subtract()) back to zero.
Once I countdown to zero, I call onComplete.
Here is the code for PendingRequests
import rx.Observable;
import rx.subjects.PublishSubject;
import rx.subjects.Subject;
/**
* Created by Admin on 6/17/15.
*/
public class PendingRequests {
private static Integer pendingReq;
private static Subject<Integer, Integer> pendingObser = PublishSubject.create();
public static void Initialize(Integer myInt) {
pendingReq = myInt;
pendingObser.onNext(pendingReq);
}
public static void Add() {
pendingReq ++;
pendingObser.onNext(pendingReq);
}
public static void Subtract() {
if (pendingReq == 0) {
return;
}
else
{
pendingReq --;
if (pendingReq == 0) {
pendingObser.onCompleted();
}
else {
pendingObser.onNext(pendingReq);
}
}
}
public static Integer Current() {
// return the current value of pendingReq for testing purposes
return pendingReq;
}
public static Observable<Integer> valueChanged() {
return pendingObser;
}
}
So from above PendingObser is a Subject and valueChanged is the Observer. (Hopefully I understand that correctly).
In my MainActivity I have two buttons. Beside each button is a textview that shows the value coming from pendingObser.
Here is the code for my two buttons
public void checkComplete(View view) {
//Intent intent = new Intent(this, ResendActivity.class);
//startActivity(intent);
PendingRequests.valueChanged().subscribe(new Subscriber<Integer>() {
#Override
public void onCompleted() {
tvPendingTotalClosed.setText("Done");
System.gc();
}
#Override
public void onError(Throwable e) {
tvPendingTotalClosed.setText(e.getMessage());
}
#Override
public void onNext(Integer integer) {
tvPendingTotalClosed.setText(String.valueOf(integer));
}
});
String myResult = seWebServiceUtils.checkCompletedRecord();
Toast.makeText(ApplicationController.getContext(), myResult, Toast.LENGTH_LONG).show();
}
public void checkOpen(View view){
// called directly from button btnCheckOpen
PendingRequests.valueChanged().subscribe(new Subscriber<Integer>() {
#Override
public void onCompleted() {
tvPendingTotalOpen.setText("Done");
System.gc();
}
#Override
public void onError(Throwable e) {
tvPendingTotalOpen.setText(e.getMessage());
}
#Override
public void onNext(Integer integer) {
tvPendingTotalOpen.setText(String.valueOf(integer));
}
});
String myResult = seWebServiceUtils.checkOpenRecord();
Toast.makeText(ApplicationController.getContext(), myResult, Toast.LENGTH_LONG).show();
}
I have two problems:
When I call checkComplete it performs as expected and will end with the word Done in tvPendingTotalClosed. However, when I hit checkOpen BOTH tvPendingTotalClosed and tvPendingTotalOpen count down. So checkComplete is not unsubscribing
After hitting the buttons the first time, if I try to hit the button CheckOpenRecords a second time nothing happens. It is like I can't re-subscribe to PendingRequests a second time.
Thanks, John

Related

RxJava - ReplaySubject only emitting data twice

I am new to ReactiveX and I have a case where I want my observable to emit data to a late subscriber(whenever the observer subscribes, observable should emit the same data that it emitted previously). I made this Observable class that provide ReplaySubject's same instance to all observers (it is singleton class).
public class AccountsObservable {
private static ConnectableObservable<String> hotObservable;
private static AccountsObservable accountsObservable;
public static AccountsObservable getObject() {
if (accountsObservable == null) {
accountsObservable = new AccountsObservable();
}
return accountsObservable;
}
public ConnectableObservable<String> getObservable() {
if (hotObservable == null) {
Observable<String> observable = ReplaySubject.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("XYZ");
emitter.onComplete();
}
});
hotObservable = observable.replay();//publish
}
return hotObservable;
}
}
Similarly, this is the observer class that creates new observer instance.
public class AccountsObserver {
AccountsFetchListener listener;
public AccountsObserver(AccountsFetchListener listener) {
this.listener = listener;
}
public Observer<String> getObserver() {
return new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String accounts) {
listener.onSuccess(accounts);
}
#Override
public void onError(Throwable e) {
listener.onFailure();
}
#Override
public void onComplete() {
}
};
}
public interface AccountsFetchListener {
void onSuccess(String accounts);
void onFailure();
}
}
Here is the function where I test these observables
private void testObs() {
ConnectableObservable<String> observable = AccountsObservable.getObject().getObservable();
Observer<String> observer = new AccountsObserver(new AccountsObserver.AccountsFetchListener() {
#Override
public void onSuccess(String accounts) {
Log.e("DATA -> ", accounts);
}
#Override
public void onFailure() {
}
}).getObserver();
observable.subscribe(observer);
observable.connect();
}
I called this function "testObs()" 5 times but it emitted data only 2 times. The problem seems to be in AccountsObservable class where I provide ReplaySUbject's instance. Thanks
Your code runs fine as it is, your logs are being suppressed in logcat as per this:
We declared an application as too chatty once it logs more than 5 lines a second. Please file a bug against the application's owner that is producing this developer-verbose-debug-level class logging spam. The logs are 256KB, that means the application is creating a DOS attack and shortening the logs timepan to 6 seconds(!) making it useless for all others.
You can avoid this behaviour by whitelisting your app for logcat:
adb logcat -P '<pid or uid of your app>'

How replace returned observable with a new one RxJava2

I have one case when I need to return an observable immediately, but then replace this observable with another one.
Here is an example
private Flowable<byte[]> mFlowableStream = Flowable.empty();
#Override
public Flowable<byte[]> startStreamRead() {
bindToService();
return mFlowableStream;
}
And then after binding to service I provide it a callback connection like that
#Override
public void bindToService() {
mAppContext.bindService(new Intent(mAppContext,StreamService.class), mServiceConnection, 0);
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
mServiceInterection = ((StreamServiceInterection.LocalBinder) binder).getServiceInteractor();
mStreamDisposable = mServiceInterection.getStream()
.subscribe(new Consumer<byte[]>() {
#Override
public void accept(byte[] data) throws Exception {
}
});
}
What I want to do is to somehow replace returned previously mFlowableStream with a new observable that I got from service.
What are possible strategies to implement this ? Maybe I should return some other value, like Future.
Please suggest how to solve this problem
Thanks
You can use Flowable.create instead of Flowable.empty
Then when new data come, just push to flowable.
Like Example
final ArrayList<FlowableEmitter<Integer>> arrEmitter = new ArrayList<>();
Flowable<Integer> futureFlow = Flowable.create(new FlowableOnSubscribe<Integer>() {
#Override
public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
arrEmitter.add(e); // hold emitter to use later
}
}, BackpressureStrategy.BUFFER);
futureFlow.subscribe(new ResourceSubscriber<Integer>() {
#Override
public void onNext(Integer integer) {
System.out.println("onNext: " + integer);
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
System.out.println("onComplete");
}
});
// =========== When data come
FlowableEmitter<Integer> holdEmitter = arrEmitter.get(0);
holdEmitter.onNext(3);
Or use you can use **Subject* type according to your need
Understanding RxJava Subject — Publish, Replay, Behavior and Async Subject

Live Data, Repository gets called multiple time android

I am working on Google's new Android Architecture Component AAC
My problem
method inside ViewModel class gets called multiple time , causing error
1 getLoggedInUser() gets called multiple times
2 Before retrofit's onNext() or onError() , the onChanged() gets called
MyActivity
LoginPojo loginPojo=new LoginPojo();
loginPojo.setEmailId(viewFunctions.getText(etLoginEmailId));
loginPojo.setPassword(viewFunctions.getText(etLoginPwd));
viewModel.loginUser(loginPojo);
viewModel.getLoggedInUser().observe(this, new Observer<LoginPojo>() {
#Override
public void onChanged(#Nullable LoginPojo pojo) {
viewFunctions.hideCustomProgress();
if (pojo.isError()) {
if (pojo.isNetworkError()) {
} else {
}
} else {
if (pojo.getStatus().equalsIgnoreCase(constants.ERROR)) {
} else {
}
}
}
});
ViewModel
private MutableLiveData<LoginPojo> mutableLogin = new MutableLiveData<>();
public final LiveData<LoginPojo> loginData = Transformations.switchMap(mutableLogin, new Function<LoginPojo, LiveData<LoginPojo>>() {
#Override
public LiveData<LoginPojo> apply(LoginPojo input) {
return repository.loginUser(input.getEmailId(), input.getPassword());
}
});
public void loginUser(LoginPojo loginPojo) {
mutableLogin.setValue(loginPojo);
}
public LiveData<LoginPojo> getLoggedInUser() {
return loginData;
}

Creating doIfEmpty operator in RxJava

I have 2 streams, the first stream is a stream which takes data from database and call onCompleted() after finish taking data. The second stream is a stream that takes live data from server and never call onCompleted(). What I want to do is to create an operator that can do an action if the first stream(upstream) is an empty stream. Here is the sample:
getItemFromDatabase()
.lift(new DoIfEmptyOperator<Item>(new Action0() {
#Override
public void call() {
//Database is empty
System.out.println("Yeay successfully do an action");
}
}))
.concatWith(getItemFromServer()) // -----> intentionally never complete
.subscribe(new Subscriber<StoryItem>() {
#Override
public void onCompleted() {
//dosomething...
}
#Override
public void onError(Throwable e) {
//dosomething...
}
#Override
public void onNext(StoryItem storyItem) {
//dosomething
}
}));
Here is the code of DoIfEmptyOperator:
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
public class DoIfEmptyOperator<T> implements Observable.Operator<T,T>{
private Action0 action;
private boolean isEmpty = true;
public DoIfEmptyOperator(Action0 action) {
this.action = action;
}
#Override
public Subscriber<? super T> call(final Subscriber<? super T> childSubscriber) {
Subscriber<T> parentSubscriber = new Subscriber<T>() {
#Override
public void onCompleted() {
if(isEmpty) {
action.call();
}
childSubscriber.onCompleted();
}
#Override
public void onError(Throwable e) {
childSubscriber.onError(e);
}
#Override
public void onNext(T t) {
isEmpty = false;
childSubscriber.onNext(t);
}
};
childSubscriber.add(parentSubscriber);
return parentSubscriber;
}
}
However the action is never executed because the parentSubscriber onCompleted() is not firing, because the downstream never completed. If I remove
.concatWith(getItemFromServer())
then the action is executed. Any clue about how to solve the problem? I have dived to the source code of Observable.switchIfEmpty() but still have no clue about how it works.
I would advise against creating an operator.
This could be easily done with existing operators like this:
getItemFromDatabase()
.toList()
.flatMap(list -> {
if (list.isEmpty()) {
// side effect here
}
return getItemFromServer();
});
Have you thought about switchIfEmpty()? As an example of the usage of this operator - I have created some code on GitHub at the following link:
https://github.com/rs146/rxjava-simple/blob/master/src/test/java/SwitchIfEmpty.java
switchIfEmpty() is called when no items are emitted.
However, if you want to get items from the api or the db, then you can do something like the following:
Observable.concat(getFromDatabase(), getFromApi()).first();
As long as both getFromDatabase() and getFromApi() return the same Observable Type. This is a common Rx idiom in Android apps. It basically states that if an item's is not emitted from the database, then go fetch the result from the API instead.

Perform requests with Retrofit inside custom Runnable

I am migrating from Volley to a custom implementation using Retrofit, but I'm trying to add to my implementation some of the Volley features that I liked, for example
RequestQueue.cancel(String tag)
If the Request has the requested tag, then it's canceled by setting a boolean value, mCanceled, to true. The run method checks this value and returns if it's true.
To be able to reproduce this with Retrofit I should be able to use my custom class implementing Runnable instead of the default one, where I have a mTag and a mCanceled field.
Moreover, Volley was also able to set such flag inside the active Threads and immediately stop them. My cancelAll method, that I've already implemented, just drains the queue to another queue, but isn't able to access the active threads.
Is it possible to achieve the same results with Retrofit and ThreadPoolExecutor?
I think I've found a nicer solution: instead of blocking the Runnable of the requests, I am blocking the Callback execution.
I have extended the Callback interface:
public interface CustomCallbackInterface<T> extends Callback<T> {
public String getTag();
public String setTag(String tag);
public void cancel();
public boolean isCanceled();
}
so that each Callback has a tag and a cancel flag. Then the success method starts with:
public class CustomCallback<ConvertedData> implements CustomCallbackInterface<ConvertedData>{
//failure...
#Override
public void success(ConvertedData cd, Response response) {
if(isCanceled()) return;
// ....
}
}
Every time I make a new request, I store the created CustomCallback inside a List cancel just iterates the list and calls cancel() on the items with the same tag.
I've implemented an easy to use class based on Vektor88 answer
public abstract class CancelableCallback<T> implements Callback<T> {
private static List<CancelableCallback> mList = new ArrayList<>();
private boolean isCanceled = false;
private Object mTag = null;
public static void cancelAll() {
Iterator<CancelableCallback> iterator = mList.iterator();
while (iterator.hasNext()){
iterator.next().isCanceled = true;
iterator.remove();
}
}
public static void cancel(Object tag) {
if (tag != null) {
Iterator<CancelableCallback> iterator = mList.iterator();
CancelableCallback item;
while (iterator.hasNext()) {
item = iterator.next();
if (tag.equals(item.mTag)) {
item.isCanceled = true;
iterator.remove();
}
}
}
}
public CancelableCallback() {
mList.add(this);
}
public CancelableCallback(Object tag) {
mTag = tag;
mList.add(this);
}
public void cancel() {
isCanceled = true;
mList.remove(this);
}
#Override
public final void success(T t, Response response) {
if (!isCanceled)
onSuccess(t, response);
mList.remove(this);
}
#Override
public final void failure(RetrofitError error) {
if (!isCanceled)
onFailure(error);
mList.remove(this);
}
public abstract void onSuccess(T t, Response response);
public abstract void onFailure(RetrofitError error);
}
Usage example
rest.request(..., new CancelableCallback<MyResponse>(TAG) {
#Override
public void onSuccess(MyResponse myResponse, Response response) {
...
}
#Override
public void onFailure(RetrofitError error) {
...
}
});
// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);

Categories

Resources