The AppNexus Mobile Advertising SDK provides developers a fast and convenient way to monetize their apps. It’s a well documented and throughly tested open-source code with direct engineering support. While implementing the Android native ad solution, I ran across a puzzling issue that I’d like to share my investigation and hopefully save other Android developers some time in the future. For those who are not familiar with native advertising, the IAB has a very clear video.
The issue was that a registration call to bond a native ad response with an Android native view would fail silently, even though the debugging tool showed that the code was executed correctly.
To simplify it, let’s pretend you’re building an app that turns on/off a flashlight, in which there’re two runnables
turnOffTheLight. You would assume that if we call
view.post(turnOffTheLight) first and then call
view.post(turnOnTheLight), the light should be on. However, in the test run, the light is actually off after execution. I put break points and stepped through the code,
turnOffTheLight was indeed posted first. Then what happened?
I downloaded the source code of Android SDK, stepped into the method
post() and found this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
It turns out that, if the view is not attached to the window, the runnable will be put in the RunQueue of the view hierachy - The run queue is used to enqueue pending work from Views when no Handler is attached. The work is executed during the next call to performTraversals on the thread.
Go back to the scenario above, when posting
turnOffTheLight the view was not attached but was attached when posting
turnOnTheLight is posted to UI thread to be executed immediately and
turnOffTheLight is not executed till the next performTraversals is called. The solution is very simple, post both runnables to the UI thread directly using the following method:
1 2 3 4 5 6 7
In the end, this is not actually a bug in the app’s code, it’s more of a rare use case exposed a slient inconvenient behavior of an Android convenience method, that the call to APIs must be done in the proper sequence to get the correct result. Sharing here with Android developers who might run into this weird situation too.