1
votes

I want to create an Observable that will emit items on demand, that means I want a single subscribe to Observable and notify Observable that I need new item based on my request.

This is what I have done using PublishSubject:

public class RecognizeSubject {

PublishSubject<Bitmap> mSubject;

private Context mContext;
private FaceDetector mFaceDetecor;

public RecognizeSubject(Context mContext) {
    this.mContext = mContext;
    this.mSubject = PublishSubject.create();
}

public void detect(Bitmap btm){
    mSubject.onNext(btm);
}

public Flowable<SinglePhotoId> execute() {
    return mSubject.toFlowable(BackpressureStrategy.DROP)
            .observeOn(Schedulers.newThread())
            .map(bitmap1 -> recognize(bitmap1))
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe(disposable -> initialize())
            .doFinally(() -> release());
}


private void initialize() {
    mFaceDetecor = new FaceDetector.Builder(mContext)
            .setTrackingEnabled(false)
            .setLandmarkType(FaceDetector.ALL_LANDMARKS)
            .build();
}

private void release() {
    if (mFaceDetecor != null)
        mFaceDetecor.release();
}

private SinglePhotoId recognize(Bitmap bitmap) {
    //SystemClock.sleep(3000);
   //make hard background work and return SinglePhotoId object
}

}

and here is a usage in Activity class:

private void takeSubjectSnap() {
    if (mSubject == null)
        mSubject = new RecognizeSubject(getBaseContext());

    if (mDisposable == null || mDisposable.isDisposed()) {
        mDisposable = mSubject.execute()
                .subscribe(this::handleDetectionSuccess,
                        this::handleDetectionError,
                        this::handleDetectionCompleted);
    }

    mSnapshotButton.setProgress(true);
    mSubject.detect(myVideoView.getBitmap());
}

So basically I subscribe to Flowable object and pass Bitmap object to my Subject class to proceed and return result via Flowable, is that solution right or can produce some memory leaks?

Is there any better solution to send an object to Observable to proceed and return result via a standard onNext() method?

3

3 Answers

0
votes

RxRelays can be handy in this situation

  1. Create a PublishRelay subject.
  2. Subscribe on it.
  3. And pass on data using publishRelaySubject.call(your_object);

https://github.com/JakeWharton/RxRelay

0
votes

(I'd put this as a comment because this is not an answer but it's too long)

I'm not really sure what is your use case here, and what exactly you're trying to achieve as the thing you described and implemented is little bit different.

What you described is a mechanism that is capable of processing some stuff and requesting new stuff when it's free/capable of processing/etc

What you implemented is a mechanism that is push-based processor processing items depending on data it receives from the clients.

So if the stuff you implemented is working as you want it's fine, but I'd suggest some little changes:

  • I'd renameexecute method to something else (as it doesn't execute anything)
  • I'd init disposable with Disposables.disposed() to avoid null check and
  • I'd rename RecognizeSubject to something else at as right now it's leaking information about it's internal implementation.
  • I'd make mSubject private and final
  • I'd get rid of hungarian notation

And I'm not really sure if flowable is appropriate thing in while working with bitmaps, are you sure you need that many bitmaps at once and process all of them (and drop the ones that were not processed?).

0
votes

OK, I have read your answer and changed my code a little, here is a diagram that illustrates what I want to achieve:

subject diagram

So my Subject class will process received data on background thread and emit processed items via onNext() method to their Observer. I made a simple Subject that receives Integer object and convert it to String object, here is the code:

public class MySubject {

private String TAG = "MySubject";

private PublishSubject<Integer> subject;
private final Observable<String> observable;

public MySubject() {
   Log.d(TAG, "---> MySubject() called");
   this.subject = PublishSubject.create();
   this.observable = subject
           .doOnSubscribe(disposable -> init())
           .doFinally(() -> relese()) //try do after terminate
           .observeOn(Schedulers.newThread())
           .map(this::myMap)
           .observeOn(AndroidSchedulers.mainThread());
}


private void init(){
   Log.d(TAG, "---> init() called");
}

private void relese(){
   Log.d(TAG, "---> relese() called");
}

private String myMap(Integer integer){
   Log.d(TAG, "---> myMap() called int: " + integer);
   SystemClock.sleep(3000);
   return " :) " + String.valueOf(integer);
}

public void decode(Integer integer){
   subject.onNext(integer);
}

public Observable<String> getObservable(){
   return observable;
}

}

And here is a usage in Activity class:

Disposable disposable = Disposables.disposed();
MySubject subject = new MySubject();

void onButton1() {

   if(disposable.isDisposed()){
       disposable = subject.getObservable()
               .subscribe(s -> {
                   Log.d(TAG, "---> onNext() called " + s);
               }, throwable -> {
                   Log.d(TAG, "---> onError() called " + throwable.getMessage());
               }, () -> {
                   Log.d(TAG, "---> onCompleted() called ");
               });
   }

   Random generator = new Random();
   int i = generator.nextInt(100) + 1;
   subject.decode(i);
}

Every time that method onButton1() is called I post new random int to subject object and after that I received processed data via onNext() method when it is finished.

Is that solution correct and doesn't cause any side effect or memory leaks? Of course I unsubscribe from subject in onStop() method of Activity. Maybe there is a better solution to handle this kind of problem in Rxjava?

Any further answers will be appreciated :)