If you haven’t followed other posts in the series, I recommend you do so before going on with this one. We have already set up a Service that can play music from the background, take care of reading local files as well as online streaming and created lock screen and notification UI for the player. Let’s take a look at how to create a UI for the music player. Although this step is largely based on the app you are working on, I will try to go into the implementation of the some widely used UI patterns in music players.

Let’s discuss how we want the UI first. A full screen blurred background for album artwork, the track artwork, title, and the playback controls. I am not gonna bore you with all the layout details. If you are interested in the the full layout file, check out this gist.

Now to the fun bits. First in queue, blurring the full screen album artwork. Again, as mentioned in the previous posts in the series, I use Glide for image loading, but you are free to switch to your library of choice. For Glide, there is already an existing set of transformations that includes blurring. Add it to your build.gradle

compile 'jp.wasabeef:glide-transformations:1.3.1'

and this to your MusicPlayerActivity:

Glide.with(this).load(album.getImagePath()).centerCrop().bitmapTransform(new BlurTransformation(this, 25, 2)).into(backgroundImageView)

The Music Player UI needs to auto update very frequently. To get a smooth UI, we set up a Runnable to be executed every 300 ms to update our UI. Here is Kotlin code to set up the Runnable, but it’s easy to adapt it to Java.

private val mRunnable = object : Runnable {
    override fun run() {
        if (isDestroyed) {
            return
        }
        setupPlayer()
        handler.postDelayed(this, 300)
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    // …
    handler.postDelayed(mRunnable, 300)
}

setupPlayer is where all the UI updates take place. We will take a look at it a bit later. First, let’s see how we can get the playback information from our MusicService. We will be converting our service to a Bound Service so that our activities can bind to the service and query about the playback. Bound Services implement the onBind method and return a Binder instance that the Activity can then use to find information about the service. Here is a simple Binder implementation that just returns the Service instance exposing all the public methods on the Service.

public class MusicService extends Service {
    private final IBinder mBinder = new MusicServiceBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class MusicServiceBinder extends Binder {
        public MusicService getService() {
            return MusicService.this;
        }
    }
}

To use this, the activity must implement ServiceConnection and then start/bind the service.

class MusicPlayerActivity : AppCompatActivity(), ServiceConnection {
    // region Lifecycle
    override fun onCreate(savedInstanceState: Bundle?) {
        // …
        val intent = Intent(this, MusicService::class.java)
        startService(intent)
        bindService(Intent(this, MusicService::class.java), this, Context.BIND_AUTO_CREATE)
    }

    override fun onDestroy() {
        // …
        unbindService(this)
    }
    // endregion

    //region Service Connection
    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        mMusicService = (service as MusicService.MusicServiceBinder).service
        setupPlayer()
    }

    override fun onServiceDisconnected(name: ComponentName) {
        mMusicService = null
    }
    //endregion
}

Now that we have everything set up, all that is left is to implement the setupPlayer() method to update the views based on the current status of the Service.

I have had far too many requests for the source code and the reason I am not putting it up is that as all source code, it requires constant maintenance and I don’t have enough time to manage this. Secondly, I have seen far too many people picking up the source code and putting it as is into the app which floods the already sub-par app market with low-quality apps aimed only for ad revenue. There is already a good, well-maintained music player source code maintained by Google if someone really needs it. Otherwise, if you need professional help, please feel free to shoot me an email.

This is the fourth tutorial in the series Building a Music Player App for Android. Stay tuned for more tutorials in this series!