PublishProcess flatMap operator does not get executed(rxjava-2) - android

I have the following code:
/**
* Request wrapped around flowable.
*/
public abstract class RequestFlowable<T> {
private final PublishProcessor<String> mPublish;
private String mName;
public RequestFlowable(String name) {
mName = name;
mPublish = PublishProcessor.create();
}
public Flowable<T> getFlowable() {
//return createAction();
return mPublish.compose(new FlowableTransformer<String, T>() {
#Override
public Publisher<T> apply(#NonNull Flowable<String> upstream) {
return createAction();
}
});
/*
return mPublish.flatMap(new Function<String, Publisher<? extends T>>() {
#Override
public Publisher<? extends T> apply(#NonNull String s) throws Exception {
return createAction();
}
});
*/
}
protected abstract Flowable<T> createAction();
public String getName() {
return mName;
}
public void start() {
mPublish.onNext("processCommand");
}
#Override
public String toString() {
return "Request: " + mName;
}
}
Now for Single
#EDIT 2
public abstract class Request<T> {
private final SingleSubject<Object> mPublish;
private String mName;
public Request(String name) {
mName = name;
mPublish = SingleSubject.create();
}
public Single<T> getSingle() {
return mPublish.flatMap(o -> createAction());
}
protected abstract Single<? extends T> createAction();
public String getName() {
return mName;
}
public void start() {
mPublish.onSuccess("Start");
}
#Override
public String toString() {
return "Request: " + mName;
}
}
The code from the above works when used with compose, like in code from above but, if instead I put the commented code - aka flatMap for some reason createAction is not executed.
EDIT 2
The code from the above is called from another class. The corresponding code is attached below(important parts of class added):
public class RequestQueue implements RequestController {
private static final String TAG = RequestQueue.class.getSimpleName();
private PublishSubject<Request> mRequest;
private PublishSubject<RequestFlowable> mRequestFlowable;
#Override
public <T> Single<T> registerRequest(Request<T> request) {
mRequest.onNext(request);
return request.getSingle();
}
#Override
public <T> Flowable<T> registerRequestFlowable(RequestFlowable<T> request) {
mRequestFlowable.onNext(request);
return request.getFlowable();
}
public RequestQueue() {
mRequest = PublishSubject.create();
mRequestFlowable = PublishSubject.create();
mRequest.subscribe(this::actionOnRequest);
mRequestFlowable.subscribe(this::actionOnRequest);
}
private void actionOnRequest(Request request) {
Log.d(TAG, "actionOnRequest() called with: request = [" + request + "]");
request.start();
}
private void actionOnRequest(RequestFlowable request) {
Log.d(TAG, "actionOnRequest() called with: request = [" + request + "]");
request.start();
}
}

(From my comments:)
Why does Single work?
SingleSubject retains the single terminal event it received. Since it can only receive onSuccess and onError, it will "replay" that to late subscribers (also this is why there is no separater ReplaySingleSubject). When you call onSuccess on the SingleSubject, that value is remembered and promplty reemitted when the later subscription happens, calling your createAction. PublishProcessor also remembers its terminal events but onNext is not a terminal event, hence dropped without consumer.
How can the desired behavior be achieved via Processor?
You could reorganize your logic, use BehaviorProcessor or ReplayProcessor.createWithSize(1). Calling onComplete won't execute the flatMap function either.

Related

How to call sequence of function in Observer in android

Currently this line "observer = data -> createTokenMap(data.getPositions());" calls a function and do some logic.
How can I accept a return value from this function and pass it into another function and so on.
public class PositionViewModel extends AndroidViewModel {
private final LiveData<PositionResponse> positionResponseLiveData;
private final Observer<PositionResponse> observer;
private final Map<String, Long> tokenMap = new HashMap<>();
public PositionViewModel(#NonNull Application application) {
super(application);
observer = data -> createTokenMap(data.getPositions());
positionResponseLiveData = PositionRepository.getInstance().getPositions();
positionResponseLiveData.observeForever(observer);
}
public LiveData<PositionResponse> getPositions() {
return positionResponseLiveData;
}
private void createTokenMap(Positions positions) {
for (Net position : positions.getNet()) {
tokenMap.put(position.getTradingsymbol(), position.getInstrument_token());
}
for (Day position : positions.getDay()) {
tokenMap.put(position.getTradingsymbol(), position.getInstrument_token());
}
}
public Map<String, Long> getTokenMap() {
return tokenMap;
}
#Override
protected void onCleared() {
super.onCleared();
positionResponseLiveData.removeObserver(this.observer);
}
}
Any help will be highly appreciated.

RXJAVA ROOM android

Trying to learn Room and RXJAVA.
I have about 80% of this understood but I'm getting stuck on figuring the rest out.
Here is the error I get on the insert data.
java.lang.NullPointerException: Attempt to invoke interface method
'void
com.example.learnroom.EntityDao.insert(com.example.learnroom.Entitys)'
on a null object reference
If I don't run the try catch I get the following error which seems to be related.
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.learnroom/com.example.learnroom.MainActivity}:
java.lang.NullPointerException: Attempt to invoke interface method
'io.reactivex.Maybe
com.example.learnroom.EntityDao.getEntity(java.lang.String)' on a null
object reference
How do I fix this?
I have tried to simplify from the tutorials all over the web most using recyclerviews to just 2 text fields. They say this is 3 pieces but it doesn't seem like it, as the DB was never set up so I ran it in a method to run the code. Maybe someone can help explain to me how this really works.
my code
Dao
public interface EntityDao {
#Query("SELECT * FROM Entitys WHERE ID = :ID LIMIT 1")
Maybe<List<Entitys>> getEntity(String ID);
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Entitys entitys);
#Query("DELETE FROM Entitys")
void deleteAllEntity();
}
Entity
public class Entitys {
#PrimaryKey
#NonNull
public String ID;
public String ts;
public String tss;
public Entitys(#NonNull String ID, String ts, String tss) {
this.ID = ID;
this.ts = ts;
this.tss = tss;
}
public String getTss() {
return tss;
}
public void setTss(String tss) {
this.tss = tss;
}
public void setID(String ID) {
this.ID = ID;
}
public void setTs(String ts) {
this.ts = ts;
}
public String getID() {
return ID;
}
public String getTs() {
return ts;
}
}
database
#Database(entities = {Entitys.class}, version = 1)
public abstract class PathwaysDB extends RoomDatabase {
private static volatile PathwaysDB INSTANCE;
public static EntityDao entityDao() {
return null;
}
public static PathwaysDB getInstance(Context context) {
if (INSTANCE == null) {
synchronized (PathwaysDB.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
PathwaysDB.class, "Pathwaysdb")
.build();
}
}
}
return INSTANCE;
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
Button tb;
EditText te, tes;
String ts, tss, ID;
CompositeDisposable compositeDisposable = new CompositeDisposable();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ID ="test";
te = findViewById(R.id.te);
tb = findViewById(R.id.tb);
tb.setOnClickListener(this);
tes = findViewById(R.id.tes);
Builddb();
try{
getData();}catch (Exception e){}
}
private void Builddb() {
Completable.fromAction(() -> PathwaysDB.getInstance(this))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onComplete() {
// action was completed successfully
}
#Override
public void onError(Throwable e) {
// something went wrong
}
});
}
private void getData() {
Maybe<List<Entitys>> single = entityDao().getEntity(ID);
single.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new MaybeObserver<List<Entitys>>() {
#Override
public void onSubscribe(Disposable d) {
// add it to a CompositeDisposable
}
#Override
public void onSuccess(List<Entitys> entity) {
te.setText(entity.indexOf(ts));
tes.setText(entity.indexOf(tss));
}
#Override
public void onError(Throwable e) {
// show an error message
}
#Override
public void onComplete() {
}
});
compositeDisposable.add((Disposable) single);
}
#Override
protected void onDestroy() {
super.onDestroy();
compositeDisposable.dispose();
}
private void updateUserName() {
ts = te.getText().toString();
tss = tes.getText().toString();
Entitys entitys = new Entitys(ID, ts, tss);
Completable.fromAction(() -> entityDao().insert(entitys))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onComplete() {
// action was completed successfully
}
#Override
public void onError(Throwable e) {
// something went wrong
}
});
}
#Override
public void onClick(View view) {
updateUserName();
Intent forward = new Intent(this, secondpage.class);
startActivity(forward);
}
}
Reason for crash is this line in your PathwaysDB class
public static EntityDao entityDao() {
return null;
}
it is returning null. It should be like
public abstract EntityDao entityDao()
You forget to add #Dao annonation to your EntityDao interface class.
also you need to change below method :
public static EntityDao entityDao() {
return null;
}
To
public abstract EntityDao entityDao();

Observable Notify Multiple variables change

How I can Notify on Multiple variables update?
Is there any method to detect and separatenotifyObservers?
public class AnimalWeightObservable extends Observable {
public long animalId;
public long weigh;
public long getAnimalId() {
return animalId;
}
public AnimalWeightObservable setAnimalId(long animalId) {
this.animalId = animalId;
this.setChanged();
this.notifyObservers(animalId);
return this;
}
public long getWeigh() {
return weigh;
}
public AnimalWeightObservable setWeigh(long weigh) {
this.weigh = weigh;
this.setChanged();
this.notifyObservers(weigh);
return this;
}
}
How can detect witch variable has changed?
How about wrapping animalId and weight inside another type: for example AnimalProperty
class AnimalProperty<T> {
String propertyName;
T property;
AnimalProperty(String name, T property) {
this.propertyName = name;
this.property = property;
}
}
so your code would look like this:
public class AnimalWeightObservable extends Observable {
public AnimalProperty animalId;
public AnimalProperty weigh;
//...
//...
public AnimalWeightObservable setWeigh(AnimalProperty weigh) {
this.weigh = weigh;
this.setChanged();
this.notifyObservers(weigh);
return this;
}
}
then in the Observer's update(...) method switch on the propertyName to know which property is updated

How to implement Observable zip with Bifunction Single and Observable?

How do I properly implement Observable.zip with Bifunction?
One returns a Single, one returns an Observable, not sure if this possible.
Thanks for the comment this is my updated. I'm not sure what to put in the BiFunction below
Observable.zip(
mCurrentUserViewModel.getUserProfile(getUserProfileRequest).toObservable(),
mTopicsByCurrentUserViewModel.getTopicsByCreator(getTopicsByCreatorRequest)),
new BiFunction<Single<GetUserProfileResponseBody>, Observable<Response<GetTopicsByCreatorResponseBody>>, **what do i put here**>()
);
you have two options to do so.
toSingle() converts an Observable which emits a single item to a Single that emits this item
toObservable converts a Single into an Observable.
for example : using toObservable()
1-create your observables
private Observable<String> getObservable() {
return Observable.just("observable");
}
private Single<String> singleObservable() {
return Single.just("single");
}
private Observable<String> mergedObservable() {
return Observable.zip(getObservable(), singleObservable().toObservable(), new BiFunction<String, String, String>() { //the result of merging is also String
#Override
public String apply(String s, String s2) {
return s + s2; //or if you are using different objects create a model AandB. where A and B are the result of a seperate observers.
}
});
}
2-merge them
mergedObservable().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
Log.d(tag,s);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
OUTPUT:
observablesingle
an example zip function :
private Observable<String> stringObservable() {
return Observable.just("D");
}
private Observable<Integer> integerObservable() {
return Observable.just(1);
}
private Observable<String> resultObservable(){
return Observable.zip(stringObservable(), integerObservable(), new BiFunction<String, Integer, String>() {
#Override public String apply(String s, Integer integer) throws Exception {
return s + integer;
}
});
}
private Observable<String> resultObservableLambda(){
return Observable.zip(stringObservable(), integerObservable(), (s, i) -> s + i);
}
The 3rd item you are missing is your return type. So what is the aggregated type you want to return - in this example String, so a new Observable Observable<String> is returned.

Return Observable<Song> from an object of SongResponse that contains a List<Song>

I have a class SongResponse:
public class SongResponse implements Parcelable {
#SerializedName("token")
public String token;
#SerializedName("items")
public List<Song> songList;
}
#GET("songs")
Observable<SongResponse> getSongs(#Query("token") String token)
In the manager class, I want to return an Observable by used the request above
public Observable<Song> syncSongs(token) {
return mSongService.getSongs(token);
....
#Override
public Observable<Song> call(List<Song> songs) {
return mDatabaseHelper.setSongs(songs);
}
}
syncSongs will call another Observer to insert songs in the database.
I used RxAndroid 2. I try to find about .map and .flatMapIterable, but don't result my problem. Could you help me complete this function?
You can try something like that :
public Observable syncSongs(token) {
return mSongService.getSongs(token).flatMap(new Function<SongResponse, ObservableSource<List<Song>>() {
#Override
public ObservableSource<List<Song>> apply(#io.reactivex.annotations.NonNull SongResponse songResponse) throws Exception {
return Observable.just(songResponse.getSongList()); //some changes here
}
}).flatMapIterable(new Function<List<Song>, Iterable<? extends Song>>() {
#Override
public Iterable<? extends Song> apply(List<Song> songs) throws Exception {
return songs;
}
}).flatMap(new Function<Song, Observable<Song>>() {
#Override
public Observable<Song> apply(final Song song) throws Exception {
return Observable.just(song);
}
});
}
Hope this helps.

Categories

Resources