Today, I ran into an unexpected, metaphorical wall: apparently, an
Activitiy embedded into another through
TabHost can’t properly bind services.
I did a little
googling research, and found that there’s a lot of confusion in the Interwebs on how to get around this limitation. Alleged solutions were mostly based on completely breaking the separation of concerns between the host
Activity and its children, passing references around and defeating the purpose of using tabs instead of just exchanging views.
In the end, I switched back from Chrome to Eclipse. After looking hard at the screen for a couple of minutes, smoking a cigarette and then staring at my code some more, I finally found a way around it (and, as so often happens, wondered why I didn’t try that from the beginning).
How to do it wrong
Let’s say you use the following code to bind a
Service to an
anActivity.bindService( new Intent(anActivity, MyService.class), aServiceConnection, Context.BIND_AUTO_CREATE );
It will work as long as
anActivity is not an embedded child. Note that the
bindService() call is made upon the same
Activity object that intends to use the connection, also passed as
Context to the
Why doesn’t it work?
I have absolutely no idea. I intend to take a look at the source and figure it out when I have the time, but seeing as it’s Saturday night, a blind fix will just have to do =).
How to do it right
Simple enough: bind the connection to the host
Activity (or maybe the global
ApplicationContext), instead of the child. There’s no need to change the
Context passed to the
Intent or to lose control over the
anActivity.getParent().bindService( new Intent(anActivity, MyService.class), aServiceConnection, Context.BIND_AUTO_CREATE );
The only catch is that, even though the
ServiceConnection can be 100% handled from the child
Service is bound to another
Context. This means that, when you no longer need it, you need to invoke
unbindService() from the same
I haven’t fully experimented with this yet, but I like the approach much better than sharing
IBinder instances or exchanging references. It preserves the encapsulation around the activities and allows each child to have its own
ServiceConnection. Also, the same
Activity can be hosted anywhere without modification, or even started independently: just checking the return of
getParent() for null should be enough to decide which
Context to use.
That’s it for today. Not a great post, but hopefully it will save someone’s time. Have a good weekend!