May 1, 2012

Tcp connections in Android

Or how to keep your app connected and stop worrying. 

This is not another place where you can find java code snippet to open a socket and read and write to some server.
If you need that, go back to your favorite search engine and look for another result. But be careful: while looking for "inspiration" I found a lot of examples where the connection was held inside the UI thread. Please, don't do that. At least use an asynctask.

Short version of this post (spolier warning):

  • If you need to interact with a tcp server, use a singleton object that contains the socket 
  • You can access it from all the activities of your app
  • If you want to be connected only while in foreground, have a counter that gets incremented on onStart() and gets decremented on onStop() of any client activity. Connect when the counter is > 0, disconnect when the counter is < 0

As a side project, I am developing a simple turn based multiplayer game, with a tcp server as backend (python twisted).

In order to make my life easier, I wanted the interaction with the server to work as follows:

  • if the player gets disconnected while playing, it can't reconnect and he is out of the current game
  • if the app goes background for any reason, it will disconnect from the server

The way the app interacts with the server is not the subject of the current post (hint: a thread for sending, one for receiving AND google protobuf for serialization), but it will probably be the subject for some code on github and another blogpost.

What I am writing about is how to share a tcp connection between several android activities.

Using a service to share the socket between android activities:

  • if you think about something that needs to survive between activities transition, a service is the first thing you think about
  • the code to interact with the server was self contained, so in every activity I had to bind to the service, wait for the bind to be done, call the service that called my code
  • because of the constraint I imposed to make the tcp server easier, I had to stop the service and restart it whenever my app went background
  • I was risking to keep the service around, consuming resources with no reason
So, use a service ONLY if you really need to keep the connection even if your app is no longer visible.
If you need to do periodical tasks, or if you need to perform one shot operations, please consider using intent services. 
Be kind and let your users know that you are draining their battery, using a notification icon when the service is alive and your app gets backgrounded.

Using a singleton to share the tcp socket:
  • A singleton object resides in your process, and so once started it's accessible from all the activities
  • You can even run one or more threads inside of it, and they will be running no matter which activity is visible
  • Not using a service, you authorize the os to suspend your application (or even to kill it) when it runs out of resources.
  • There is no need to have the service layer to bind from the activity, you can access directly your singleton object
So, this is the BEST WAY to share a tcp connection between activities.

But what if you want to connect only when the application is foregrounded?

How to check when your application is active:
Have a global counter (a good place might be the singleton itself) that gets incremented every time an onStart() is called from one of your activities, and decremented when onStop() gets called. 

If that counter is > 0, that means the (at least) one activity is active and then the socket must be connected.
On the other hand, if the counter gets to 0, no activity is visible and so you need to disconnect.

If you are afraid that the counter might go to 0 only because an activity is starting another one and so its onStop() gets called before onStart of the next one, please note that the official android documentation assures us that when starting one activity from another,  onStop gets called AFTER onStart() of the started activity

With that in mind, we are sure that the only time the counter will get to 0 is when the ALL the activities are stopped.

If you liked this post, please consider following me on twitter @fedepaol .

comments powered by Disqus