booeyoh
booeyoh

Reputation: 91

Single.Create()...blockingGet() hangs in RxJava 2.1.3 when using Android/Firebase Realtime Database

When using the following pattern to synchronously get data from Firebase Realtime Database:

String s = Single.create(new SingleOnSubscribe<String>() {
    @Override
    public void subscribe(SingleEmitter<String> e) throws Exception {
    FirebaseDatabase.getInstance().getReference("path").orderByChild("child").equalTo("xyz").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
        e.onSuccess("Got it");
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
        e.onError(databaseError.toException());
        }
    });
}
}).blockingGet();

It will hang and create an ANR error. If I use the same Firebase "innards" outside of the Single, it fires just fine. The Single without the Firebase code inside also will fire, so it seems there is some incompatibility between the two.

Any ideas?

Upvotes: 4

Views: 4718

Answers (2)

Umer Farooq
Umer Farooq

Reputation: 7486

Since you are creating your own Single, You should use DisposableSingleObserver in subscribeWith. Secondly, you shouldn't be calling blockingGet() like that. The reason is by default the Single or any observable/Processor/Flowable you create will be subscribed (run its operations on main thread) and observe on main thread. BlockingGet() causes the mainThread to pause. It's like executing Thread.sleep() on Main Thread. This always ends in a disaster.

The best option for you would be to rethink the logic you are trying to put in to the code. Since the Firebase operations are Async by nature, you should adapt your code to async pattern.

Anyways you can do something like the following to achieve what seems likes you might be trying to do. Note that I wrote the following code here so it might have syntactical errors.

   Single.create(new SingleOnSubscribe<String>() {
        // your firebase code
    @Override
        public void subscribe(SingleEmitter<String> e) throws Exception {

  FirebaseDatabase.getInstance().getReference("path").orderByChild("child").equalTo("xyz").addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
            e.onSuccess("My String");
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
            e.onError(databaseError.toException());
            }
        });
       }
    })
    .subscribeOn(Schedular.io())
    .observeOn(AndroidThread.mainThread()) // if you aren't doing intensive/long running tasks on the data you got from firebase
    .subscribeWith(new DisposableSingleObserver<String>() { 
         public void onSuccess(String myString) {
               mMyString = myString;
         }
         public void onError(Throwable t) {
            Timber.e("error in fetching data from firebase: %s", t);
         }
     });

Upvotes: 1

m.ostroverkhov
m.ostroverkhov

Reputation: 1960

Firebase delivers events on ui thread, waiting for result with blockingGet deadlocks it. In my opinion you should rethink app logic and subscribe without blocking with subscribe(SingleObserver)

Upvotes: 1

Related Questions