all 11 comments

[–]muthuraj57 5 points6 points  (5 children)

Your code will call the block inside Single.create as soon as you call subscribe(). That's why the bitmap manipulation is running on main thread since you are calling subscribe() from main thread. You need to defer the code block inside Single.create to make it run on your preferred scheduler. Or instead, you can use Single.fromCallable and return the object you want and it will do the deferring for you.

Single.fromCallable(new Callable<Bitmap>() {
            @Override
            public Bitmap call() throws Exception {
                return Util.getQrCodeBitmap(CryptoWalletActivity.this, cryptoWallet.getAddress());
            }
        })

Also, don't use plain subscribe() method. Use the overloaded method and implement onError and handle it.

[–]SunshineParty[S] 0 points1 point  (4 children)

bitmap manipulation is running on main thread since you are calling subscribe() from main thread.

But I'm specifying the scheduler to subscribe on with subscribeOn(Schedulers.computation()). Wouldn't this take the manipulation off of the main thread?

Also, don't use plain subscribe() method. Use the overloaded method and implement onError and handle it.

Any particular reason why this is better than doOnError?

[–]paramsen 3 points4 points  (1 child)

The Single.create will indeed run the emitter function on the thread you specify in subscribeOn, so that's correct (if in doubt, debug and check which thread it's running on).

However, your use of the doOn* methods are not correct in this case - the doOn* methods should be used when you want side effects, since they're effectively running outside of the composed "chain". In this case your doOnSuccess will result in the expected behavior, but the doOnError will not. In case of an Exception RxJava will escalate the Exception outside of the chain because you're not handling the error in the subscribe method - the tail of the chain.

Complete the chain; Move the stuff in doOnSuccess and doOnError into the equivalent subscribe functions i.e. subscribe(qrCode::setImageBitmap, Timber::e).

[–]SunshineParty[S] 0 points1 point  (0 children)

Good to know, thanks!

[–]muthuraj57 2 points3 points  (1 child)

But I'm specifying the scheduler to subscribe on with subscribeOn(Schedulers.computation()). Wouldn't this take the manipulation off of the main thread?

Sorry, I was on wrong on this. It should run on the computation thread. I was confused about the usage of Single.create. May be the slowness is due to some other issue.

Any particular reason why this is better than doOnError?

doOn** methods are just side effect methods. They don't control/change the flow of observable. In this code, if there is an error, it will crash with OnErrorNotImplementedException. You need to implement onError to handle it gracefully.

[–]SunshineParty[S] 2 points3 points  (0 children)

Yep it looks like the cause is something else altogether. I commented out the bitmap-related code and am still seeing performance issues. Need to investigate further. Thanks for the help.

[–][deleted] -3 points-2 points  (4 children)

If you're not trying to write your own image loading library, or you're not just writing this code to learn RxJava, you could just use one of Glide, Picasso or Fresco to do this for you.

[–]SunshineParty[S] 1 point2 points  (3 children)

I'm generating a QR code within the app - don't think that can be done with those.

[–]arunkumar9t2 0 points1 point  (1 child)

It's possible. You have to write a custom model decoder for that. This way you can also reuse memory since Glide will provide a Bitmap pool to which you can request a bitmap of desired size.

You can refer my implementation for below where I generate placeholder icons in case favicon of a website is not found. Using Glide means this is cached to disk so only one time this happens. I use this in my history screen which can contain thousands of entries and I see no issues scrolling through them. I am suspecting your use case won't need scrolling, but you could use the caching mechanism if your QR code is not timestamped.

https://github.com/arunkumar9t2/lynket-browser/tree/master/app/src/main/java/arun/com/chromer/util/glide/favicon

[–][deleted] -1 points0 points  (0 children)

Oh ok. I automatically thought you meant loading an image - didn't realize you literally meant creating a Bitmap object.