This is the final of the 6 post series where we built a music player app from scratch. A quick recap of what we have done so far. We learned the basics of playing music using Media Player on Android. The Media Player is implemented in a Service so we can play music in the background. It also includes a notification, lock screen controls, and a foreground app UI. Finally, we learned how to create a mini toolbar that we can embed on all activities.

Now that we have everything set up, adding playlist support is going to be pretty simple. Let’s start by creating a Realm model for saving our playlists locally.

@Parcel(value = Parcel.Serialization.BEAN, analyze = arrayOf(Playlist::class))
open class Playlist : RealmObject() {
    @Required
    @PrimaryKey
    open var objectID: String = UUID.randomUUID().toString()
    @Required
    open var title: String = ""
    @Required
    open var createdAt: Date = Date()
    @Required
    open var lastUpdatedAt: Date = Date()
    open var files: RealmList<AlbumFile>? = null
        @ParcelPropertyConverter(AlbumFile.AlbumFileListParcelConverter::class) set
}

Now, we need to allow users to add songs to the playlist. I will leave the UI implementation as an exercise for the reader. Let’s discuss the core logic of loading a list of songs the user can select from and actually adding these songs to the playlist.

val albums = realm?.where(Album::class.java)?.findAll() // Load all albums
// …
// Load all files in an album
fun getFilesForType(type: AlbumFile.AlbumContentType): List<AlbumFile> {
    val files = this.files.let { it } ?: return ArrayList<AlbumFile>()
    val typeFiles = ArrayList<AlbumFile>(files.size)
    for (file in files) {
        if (file.file != null && file.type == type) {
            typeFiles.add(file)
        }
    }
    return typeFiles
}

After the user has finished selecting all files to add to the playlist, we need to signal a result to the parent activity using setResult.

data.putParcelableArrayListExtra(PlaylistEditActivity.EXTRA_FILES, ArrayList(mFiles.map { Parcels.wrap(AlbumFile::class.java, it) }))
setResult(RESULT_OK, data)
finish()

Finally, in the parent activity, handle the result in onActivityResult and add the songs to the playlist.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode != Activity.RESULT_OK || data == null) {
        return
    }

    when (requestCode) {
        REQUEST_CODE_SONGS_PICKER -> {
            if (mPlaylist?.files == null) {
                mPlaylist?.files = RealmList()
            } else {
                mPlaylist?.files?.clear()
            }
            data.getParcelableArrayListExtra<Parcelable>(EXTRA_FILES).map { Parcels.unwrap<AlbumFile>(it) }.forEach { mPlaylist?.files?.add(it) }

            // UI Update Adapter and clear any errors
        }
    }
}

That’ all you need to start saving your playlists in a Realm database. Once this is done, it is just basic UI to load your playlists and play the songs. Refer to Creating a Music Player UI on Android to check out how to play the songs saved in your playlist.

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.