In a perfect world you would just open your laptop and tell android studio to make you a fully functional music player app and it will just do it, but Nah, this is not the case here, so let’s find out how it works.
Try the player
In a another perfect world you would just extract your audio file and put it in the player and tell the player to start and when you leave the activity the player will just disappear, but most of the time this is not the case, but let’s start with this case just to understand how this player works.
Let’s start with dependencies :
Okay, now we need to add some audio file to play it, I added one in the assets called heart_attack.mp3
The player prepares a MediaSource then play when you set player.playWhenReady to true, which means you can pause it setting player.playWhenReady to false 🤷 :
Let’s play it :
Now when you run the app it works just fine 🤩 and you don’t need to handle any of Audio Focus crap 🙏
OK, it’s pretty easy till now I think, but music player should use a service so we can play it in the background even with this activity destroyed, try and press back button and you will still hear the music because we didn’t release the player but the problem is when you open the app again the song starts from the beginning, actually there are tons of problems with the music player running in the activity so we need to do more work 🔨 grab your coffee ☕.
Media App Architecture
You are a developer so you know that bad architecture is a nightmare, maybe worse.
You can go read that in here, but here I will talk about how I see it.
You have two sides, one is the UI from where you send your events like start, stop, pause, etc.. and the other one is the service running the player where you respond to these events, you also have a “Browser” in the middle which “connects” the UI events to the service responses.
The UI events are handled using the MediaController, and add Compat for backward compatibility for APIs below 21 and as the guide says it’s the best practice so it’s MediaControllerCompat, in this class you will find getTransportControls() that returns TransportControls object which you use to stop(), play(), pause() etc..
The service responses are handled using MediaSessionCompat.Callback where you can find onPlay(), onStop(), onPause() etc, as the name indicates the TransportControls#stop() triggers Callback#onStop and so on.
Let’s get into the code.
Our service must extend MediaBrowserServiceCompat.
Well the code explains itself 🏂
Once again, understanding that code is pretty simple, give it a shot.
No, we aren’t done!💔
This player is pretty good, it has some problems though, you are a great developer you can handle them easily but if you consider waiting till the next article that will be great, so what are these problems ?
1- Start the music, open another music app and play music from it, then pause the other app’s music, see ? your app is not continuing to play the music 😔.
2- After you do one go back to your app you will find it in STATE_PLAYING as you didn’t update the PlaybackStateCompat.
3- No beautiful artwork or any data about the song 😞.
4- No seek bar, you can’t skip the first 50 minutes of music to the 30 seconds of the real singing part 😣.
5- Did you notice I totally ignored onLoadChildren and onGetRoot ?
6- Also No notification to control the flow of the music when the app is closed.
I didn’t want to bring it all together that would make it harder to understand, I just want you to understand this part and the interactions happen between these classes and that is enough for today.