PlayerService
Amdroid Player Service
The Problem
Well, one of the more annoying things with Amdroid is the fact that you really can’t listen to music and access another application without the Android OS deciding to kill Amdroid on you. This sucks, a lot.
What I had in mind
A very common solution in the Android world to this problem is to create a service that runs separately from the visible app, and have a higher task priority, so it doesn’t get killed so easily.
The Android SDK has two types of services: start/stop and bound (bind/unbind)
Since I needed to do some complex IPC (interprocess communication) I decided to go with the bound services which allow me to write an aidl file specifying all of the functions that are available to the client from the server.
So, to start and bound service, you just initiate a bind call to the service, and if the service has not been started yet it will start, and provide you with the aidl interface to communicate with the service.
One of the interesting things about the aidl files, is that you can only use basic types of data like Strings, Integers or Booleans. For custom objects you have to write parceable functions within the object declarations so Java knows how to transfer and read the object over a text stream.
This really complicates things if you need a list or arraylist, so you pretty much only have a basic array available if you want a list of custom objects sent to the service (in our case a list of Media objects).
Problems
I had three major problems when implementing the service feature in Amdroid.
The first was the parceable functions for the custom objects. Data is not magically transformed into a text stream, so inherited information from the super classes also must be packaged up in the parceable as well… For example the information from the ampacheObject class when passing a Media object. Or even the information from the Video class when passing a Media object around.
The second major problem was trying to initiate the service. This particular issues was made of two smaller sub-problems. Firstly, I was trying to initiate classes and objects too early in the service creation. For example, initiating the Player object in the constructor rather than in the onCreate function. Secondly, I wasn’t calling the correct function from the Android Intent (this one took me the longest to figure out). Below is the “proper” formatting of calling another class as a service:
PlayerServiceClient.java
Intent intent = new Intent();
intent.setClassName( "com.sound.ampache", "com.sound.ampache.service.PlayerService" );
AndroidManifest.xml
<service android:enabled="true" android:name=".service.PlayerService"/>
Notice in the intent, the first part “com.sound.ampache” points to the root of the application, not the file you are working in. And the second part “com.sound.ampache.service.PlayerService” points to the root class of the service. This must be exact, or you won’t be able to start the service.
In the AndroidManifest.xml you have to specify exactly where the service class is for Android to know that you want to compile it separately as a service.
The third major problem was trying to get the data from the service to the client. Normally in an application you retrieve a lot of settings in the constructor or onCreate; however, with a service, you have to make sure that service has been fully started before you start retrieving/setting various things located in the service. Thus you have to wait until after the constructor and the onCreate functions have been completed (I had to comment out a bunch of Amdroid code because of this).
TODOs
- Notifications
- Client callbacks (Server –> Client messaging)
- External access to the service
- Life-cycle analysis
- Service gets killed when the playlist is finished, and Amdroid is not visible

