Reactive Ad Loading with RxAds

Shaishav Gandhi
AndroidPub
Published in
3 min readMay 30, 2018

A post about ads (the thing that every body likes to see on their screen) and how to load them (that is taken care by a third party SDK)? Yup, I realize I’m serving to a niche audience with this post, but hey, ads are important as hell.

Software is a unique commodity where people almost expect products to be free of cost despite countless hours put in the free time of an indie developer. For us developers, ads are a great way to get audience to our products and still make a little money.

Ad loading and serving is a well solved problem, with robust SDKs. For the purposes of this article I’m going to talk about Google Play Services Ads SDK and working on a reactive wrapper around the Ads APIs.

Existing API

Let’s take an example of loading a Native Content Ad. This existing API looks something like this:

While this is a decent API, there are a few problems with it:

  • Callbacks are fine for ad loading when you just want to set it to view. However, if you want to then do some other asynchronous work (like fire off a network request to your analytics or get some more data from your own data sources) then you enter callback hell.
  • No default callback for ad failed to load. You have to remember every time to add a withAdListener() callback to it.
  • Further more, the error code is obscure and you’ll have to either go and look it up every time or have some kind of mapper that will tell you what actually went wrong

So I decided to write a small utility library for this, which will give us all of those points.

Enter RxJava and RxAds

The great thing about RxJava is its composition and error handling which we can apply to this problem.

The same API then becomes:

Let’s break this down:

RxAdLoader

RxAdLoader is your entry point to loading a new ad. Internally, RxAdLoader extends AdLoader and so it inherits all of its methods. This decision was consciously made so as to be able to easily extend all functionality that AdLoader already provides and will provide in the future.

Since RxAdLoader inherits from AdLoader, you initialize it as usual with a context and an ad_unit_id. From here, you go about chaining operators to RxAdLoader as you normally would. This gives you:

new RxAdLoader(context, "ad_unit_id")
.withNativeAdOptions(new NativeAdOptions.Builder()
// Add options here
.builder())

Similar to withNativeAdOptions you can chain other operators as well and whenever you’re done you call loadNativeContentAd and pass your AdRequest instance.

This complete API looks like:

new RxAdLoader(context, "ad_unit_id")
.withNativeAdOptions(new NativeAdOptions.Builder().build())
.loadNativeContentAd(new AdRequest.Builder().build())
.subscribe();

Multiple Ads

RxAds also supports loading multiple ads and exposes an Observable instead of the usual Single. Example request:

AdLoader.Builder(this, "ad_unit_id")
.loadInstallAds(AdRequest.Builder().build(), 3)
.subscribe({ ad ->
// Get a stream of ads
}, { error ->
// Handle errors, if any
})

Error Handling

As I mentioned before, one of the problems with error handling in Play Services SDK was that an integer with the error code was passed. You would then have to look up the error yourself online and find out whether there was a network error etc. With RxAds, not only do you get error handling for free (with RxJava’s onError) callback, but RxAds also wraps your error into a more friendlier stacktrace which contains the error code as well as the human readable form of it’s meaning. This helps tremendously in development time as well as logging them to Crashlytics.

Kotlin

RxAds also has first class Kotlin support (in fact, it is written entirely in Kotlin!). There’s no point having the same API as the Java version since we wouldn’t be leveraging one of the most powerful Kotlin features: extension functions.

RxAds provides Kotlin extensions for most APIs so that you can build your AdLoader.Builder in a normal way and then just call the appropriate API.

Some examples:

AdLoader.Builder(this, "ad_unit_id")
.loadInstallAd(AdRequest.Builder().build())
.subscribe({ installAd ->
// Set to view
}, { e ->
// Handle error
})

Or load an InterstitialAd

val ad = InterstitialAd(this)
ad.adUnitId = "ca-app-pub-3940256099942544/1033173712"
ad.asSingle(AdRequest.Builder().build())
.subscribe({ ad ->
ad.show()
}, { error ->

})

That’s a wrap

You can find the source and details on installing it here. It will be really interesting to get people’s use case and integrate them in the library! Give it a shot and open an issue if you find any bugs!

Happy coding!

--

--