Search code examples
rx-javarx-java2behaviorsubject

Rxjava combineLatest - why is BiFunction called twice when only one subject changed?


I wrote a simply example in hopes someone can help me understand this code and why its printing the text in the Bifunction twice:

 var subject1: BehaviorSubject<String>? = null
    var subject2: BehaviorSubject<String>? = null





   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.v("mytag", "oncreate called now")
        subject1 = BehaviorSubject.createDefault("hello")
        subject2 = BehaviorSubject.createDefault("goodbye") //not subscribed to


        subject1?.subscribe { Log.v("subject1 it1", it) }


        btn.setOnClickListener {
            subject1?.onNext("hello btnclicked" + Random().nextInt(9000))

            ObservableCombineLatest.combineLatest(
                    subject1,subject2, BiFunction<String,String,String>
            { t1, t2 -> "biFun call" }).
                    subscribe { msg-> Log.d("mytag","combined latest update: $msg")}
        }
    }

}

when i click the button on the first try, this is the output:

 07-13 00:55:09.124 10559 10559 D mytag   : combined latest update: biFun call
07-13 00:55:09.130 10559 10559 D mytag   : combined latest update: biFun call

but why ? only one subject has changed, thats subject1 variable. when i click the button its invoking onNext which starts an emission. Why is it printing twice ? i am expecting since subject2 is never used it will not fire.


Solution

  • This works for me:

    import org.junit.Test;
    
    import io.reactivex.subjects.BehaviorSubject;
    import io.reactivex.Observable;
    
    public class BehaviorSubjectCombineLatest {
    
        BehaviorSubject<String> subject1;
        BehaviorSubject<String> subject2;
    
        @Test
        public void test() {
            subject1 = BehaviorSubject.createDefault("hello");
            subject2 = BehaviorSubject.createDefault("goodbye");
    
            subject1.subscribe(v -> System.out.println("Subject1 it1: " + v));
    
            click();
        }
    
        void click() {
            subject1.onNext("hello button clicked " + System.currentTimeMillis());
    
            Observable.combineLatest(subject1, subject2, 
                (a, b) -> "biFun call " + a + ", " + b)
            .subscribe(v -> System.out.println("Combined latest: " + v));
        }
    }
    

    prints:

    Subject1 it1: hello
    Subject1 it1: hello button clicked 1531467839204
    Combined latest: biFun call hello button clicked 1531467839204, goodbye
    

    However, if you "click" multiple times, you'll create more and more combineLatest and thus even more repeated printouts. With three clicks:

    Subject1 it1: hello
    Subject1 it1: hello button clicked 1531467945206
    Combined latest: biFun call hello button clicked 1531467945206, goodbye
    Subject1 it1: hello button clicked 1531467945240
    Combined latest: biFun call hello button clicked 1531467945240, goodbye
    Combined latest: biFun call hello button clicked 1531467945240, goodbye
    Subject1 it1: hello button clicked 1531467945242
    Combined latest: biFun call hello button clicked 1531467945242, goodbye
    Combined latest: biFun call hello button clicked 1531467945242, goodbye
    Combined latest: biFun call hello button clicked 1531467945242, goodbye