v0.3.6 (Mar 21, 2014)
Oct 21, 2015
Apr 20, 2016 (Retired)
Rebecca Nesson (rebeccanesson)
Andrew Kuklewicz (kookster)
Chris Quamme Rhoden (cqr)
Source code



PlayerHater is an Android library for playing audio in the background of your app. You can use it for:

  • Podcasts!
  • Music!
  • Radio!

You probably shouldn't use it for:

  • Fart sounds
  • Game sound effects

There's a whole lot that PlayerHater does for you right out of the box and you can add your own functionality through the use of plugins. PlayerHater even ships with plugins that will do the following automatically:

  • Show a regular notification on on Android 2.3 or lower, a notification with player controls on Android 3.0+, and an expandable notification on Android 4.2+!
  • Handle audio focus changes in all of the weird and different ways for pre-2.2 and post-2.2 versions!
  • Add lock screen controls on Android 4.0+!
  • Pebble support!

All of this is configurable if you like, and you can write your own plugins to run alongside these.

But the best thing about PlayerHater is that there are no ServiceConnection callbacks, MediaPlayer state diagrams, or setup and teardown code for you to write. It's all taken care of in the library.

Quick Start

Important, temporary information

Everything's going into Maven Central soon using the new aar format
that's part of the new Android build system that uses Gradle. If
you're not comfortable using the sonatpe OSS snapshot server (or if
you don't know what that is) or you haven't moved to Gradle yet, you
can check out the project repository and use the files in 


as if they were a normal android library project. They are, in fact

Note that doing this will require you to add entries to your
AndroidManifest.xml file, while the new build system allows us to
automatically do this for you if you're using Gradle.

Once you've imported the project into your android application and added the Service and BroadcastReceiver to your AndroidManifest.xml file, getting a handle on the player is as easy as:


class MyApplicationActivity extends Activity {

 private PlayerHater mPlayerHater;

 public void onResume(Bundle savedInstanceState) {
  mPlayerHater = PlayerHater.bind(this);
 public void onPause() {


When you've bound to a PlayerHater, you're ready to start playing stuff - music, podcasts, or whatever new thing the kids are listening to these days.

The PlayerHater API

 abstract void emptyQueue()
 Removes all songs from the queue.
 abstract int enqueue(Song song)
 Puts a song on the end of the play queue.
 abstract int getCurrentPosition()
 Gets the location of the playhead in milliseconds.
 abstract int getDuration()
 Gets the duration of the currently loaded Song in milliseconds.
 abstract int getQueueLength()
 Returns the number of items in the queue.
 abstract int getQueuePosition()
 Returns the number of clips in the queue which are at least partially behind the playhead.
 abstract int getState()
 Gets the state of the PlayerHater, represented as an int.
 abstract boolean isLoading()
 Checks to see if the player is currently loading audio.
 abstract boolean isPlaying()
 Checks to see if the player is currently playing back audio.
 abstract Song nowPlaying()
 Gets the Song representation of the track that is currently loaded in the player.
 abstract boolean pause()
 Pauses the player.
 abstract boolean play(Song song, int startTime)
 Begins playback of song at startTime
 abstract boolean play(Song song)
 Begins playback of a song at the beginning.
 abstract boolean play(int startTime)
 Begins playback of the currently loaded Song at startTime in the track.
 abstract boolean play()
 Begins playback of the currently loaded Song.
 abstract boolean removeFromQueue(int position)
 Removes the element at position from the play queue.
 abstract boolean seekTo(int startTime)
 Moves the playhead to startTime
 abstract void setPendingIntent(PendingIntent intent)
 Sets the intent to be used by the plugins.
 abstract void setTransportControlFlags(int transportControlFlags)
 Sets the visible buttons for plugins.
 abstract void skip()
 Moves to the next song in the play queue.
 abstract void skipBack()
 Moves back in the play queue.
 abstract boolean skipTo(int position)
 Moves to a new position in the play queue.
 abstract boolean stop()
 Stops the player.



We refactored everything to make more sense and run faster. Large parts of the codebase have been written from scratch using knowledge we gained in versions 0.1.0 and 0.2.0 and many class and method names have been changed to make more sense.

0.3.0 is a breaking upgrade from 0.2.0 and is still considered beta software until a 1.0.0 release.


  • The Service is now aggressively bound whenever you are interacting with PlayerHater. It's still released when appropriate so that Android can GC the process automatically and it will not show up in the Android Running Services list.

  • getState() will now return one of PlayerHater.IDLE, PlayerHater.PLAYING, PlayerHater.LOADING, or PlayerHater.PAUSED instead of one of the lower-level MediaPlayer states.

  • public Bundle getExtra() and public String getAlbumTitle() have been added to the Song interface. void onAlbumTitleChanged(String albumTitle) has been added to the PlayerHaterPlugin interface.

  • void onServiceStarted(IPlayerHaterBinder binder) has been removed from the PlayerHaterPlugin interface. If you need access to Service-only methods, check to see if the PlayerHater passed to onPlayerHaterLoaded() is a ServicePlayerHater, cast, and then call the methods needed.

  • Song data is loaded just in time, even across the IPC boundary. This means that if you enqueue a Song and then the return values for the various Song methods change, those changes will be propagated. Please note that if your Activity-side application is terminated the Song data will be serialized at that moment and passed across the barier to permit garbage collection.


  • No service callbacks to deal with - Service is automatically started as needed when play() is called. You can immediately work with PlayerHater and all commands sent to it will be forwarded to the Service once it is started.

  • It is no longer the developer's responsibility to remember when to and when not to stop the service.

  • The service is now runnable on a separate Android process through the use of AIDL IPC.

  • Too many changes to enumerate. Refer to documentation.

0.2.0 is a breaking upgrade from 0.1.0 and is still considered beta software until a 1.0.0 release.


To get started, sign the Contributor License Agreement.


Copyright 2013 Chris Rhoden, Rebecca Nesson, Public Radio Exchange
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.