I have a song list and I want to play it in order. So after the song ends, it plays the next song. Here's what I try so far in my MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
var flag = 0
//play the first song
player = MediaPlayer.create(this,songResources.getValue(songList[0]).rawId)
player.start()
//play the next song in order after each of the song ends
player.setOnCompletionListener {
flag++
player = MediaPlayer.create(this,songResources.getValue(songList[flag]).rawId)
player.start()
}
After the first song ends, the second song starts playing. But after the second song ends, the third song didn't start playing. How can I fix this?
It looks like you just need to set your flag variable as a class level variable (i.e. not inside the onCreate() function).
Try declaring private var flag = 0 above onCreate() and see if that works.
In my app there is a "Start" button.
The desire result is whenever the media player is playing,the text of the button should be change to "Stop", and when the music stops the button text should change back to "Start".
I tried doing "Do While Loop" as a solution, but even when media player isn't playing,the text is changed.
Is this the right solution ?
Why does it work even when mainViewModel.mediaPlayer.isPlaying is false?
This is what I tried:
private fun trackPlayButtonTransformation() {
do {
rootView.speakButton.text = "Stop"
} while (mainViewModel.mediaPlayer.isPlaying)
}
mainViewModel.mediaPlayer:
var mediaPlayer = MediaPlayer()
Thanks!
In a do while, the first instruction is ran no matter what, therein lies your problem. Do a regular while
private fun trackPlayButtonTransformation() {
while (mainViewModel.mediaPlayer.isPlaying) {
rootView.speakButton.text = "Stop"
}
}
Even this is clearly missing, you want to set the text to Play if the condition is'nt met.
You should probably use an actionListener on the button itself, and do a switch
const button = findById...... You should be able to find that easily.
button.addEventListener('click', buttonIsClicked())
private buttonIsClicked () {
if ( mainViewModel.mediaPlayer.isPlaying ) {
// stop that song
// change the text
}
else {
// play that song
// change the text
}
}
this is a rought draft, but this kind of is how I would do a play button.
I try to play and pause an audio file on the same button in my recyclerView adapter. But if I press my "playbtn" it just play and not pause.
Here is my function:
fun playmusic(position: Int) {
val post = posts[position]
mp = MediaPlayer()
mp.setDataSource(post.audioUrl)
mp.prepareAsync()
mp.setOnPreparedListener { player ->
if (player.isPlaying)
player.pause()
else{
player.start()
}
}
}
Here is my clickListner:
playbtn.setOnClickListener {
playmusic(postPosistion)
Toast.makeText(context, "You play ${postPosistion + 1}", Toast.LENGTH_SHORT).show()
}
Every View object has a method called setTag/getTag, this is used to store small info about the state of the view.
In your 'play' button's click listener, you can set tag with your custom state, it could be anything, an integer, a string, or even a sealed class states. After then, it's just simple if-else logic, in your if condition, check if the getTag as T(the type of object you previously-stored), matches playing state, then pause else play.
I have a list of songs i put manually inside my app and it currently have 3 functions: start, pause and stop (using ImageViews).
The problem is that i can play multiple songs at the same time that is not supposed to be like that. I really cant find the issue here and hope someone can help.
This is a demonstration on my problem
I want it to STOP currently playing song when another song is being clicked on.
Here is my code for my play button:
viewholder.playB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (currentSong == null || song != currentSong) {
currentSong = song;
mediaPlayer = MediaPlayer.create(context, song.getSong());
}
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
viewholder.playB.setImageResource(R.drawable.play_black);
} else {
mediaPlayer.start();
viewholder.playB.setImageResource(R.drawable.pause_black);
}
}
});
Instead of always creating a new instance of MediaPlayer every time the event onClick is called, you should create a single instance and reused it.
To play a new song don't forget to reset your player first. Here is an example:
mPlayer.reset();
mPlayer.setDataSource(context, song.getSong());
I searched two days for this question in github but i can't find true answer . I want example for detecting pause / resume in ExoPlayer > 2.x .
Any one can give me an example ? I checked onPlayerStateChanged and problem not solved .
onPlayerStateChanged : STATE_BUFFERING
onPlayerStateChanged : STATE_READY
I just got this log from onPlayerStateChanged and this is not called in all times !
EDIT---
Please refer to the Player.isPlaying() method which provides this as an API.
"Rather than having to check these properties individually, Player.isPlaying can be called."
https://exoplayer.dev/listening-to-player-events.html#playback-state-changes
--- EDIT END
You need to check playWhenReady with a Player.EventListener. The Playback states of ExoPlayer are independent from the player being paused or not:
player.addListener(new Player.DefaultEventListener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playWhenReady && playbackState == Player.STATE_READY) {
// media actually playing
} else if (playWhenReady) {
// might be idle (plays after prepare()),
// buffering (plays when data available)
// or ended (plays when seek away from end)
} else {
// player paused in any state
}
}
});
To play/pause the player ExoPlayer provides
player.setPlayWhenReady(boolean)
The sequence of playback states with ExoPlayer with a media file which never stalls to rebuffer is once in each of the four states and does not express play/paused:
Player.STATE_IDLE;
Player.STATE_BUFFERING;
Player.STATE_READY;
Player.STATE_ENDED;
Each time the player needs to buffer it goes:
Player.STATE_READY;
Player.STATE_BUFFERING;
Player.STATE_READY;
Setting playWhenReady does not affect the state.
All together your media is actually playing when
playWhenReady && playbackState == Player.STATE_READY
It plays when ready. :)
You can use this function:
public boolean isPlaying() {
return exoPlayer.getPlaybackState() == Player.STATE_READY && exoPlayer.getPlayWhenReady();
}
It must be that since the other answers were posted, a new method has been provided in Player.EventListener. [EDIT: Now it is Player.Listener, as Player.EventListener has been deprecated]. This works well for me:
override fun onIsPlayingChanged(isPlaying: Boolean) {
// your code here
}
If isPlaying is false, it is paused, otherwise playing.
I had the same requirement to detect the click event of exoplayer play/pause button. Above answers were mainly talking about the state not
about the button click event.
This is what I did to detect the Play/Pause button click, works perfect.
Step 1: Create custom control dispatcher class and override the method dispatchSetPlayWhenReady
class PlayerControlDispatcher : DefaultControlDispatcher() {
override fun dispatchSetPlayWhenReady(player: Player?, playWhenReady: Boolean): Boolean {
if(playWhenReady) {
// Play button clicked
} else {
// Paused button clicked
}
return super.dispatchSetPlayWhenReady(player, playWhenReady)
}
}
Step 2: Set the custom control dispatcher class PlayerControlDispatcher into the the player view.
playerView.setControlDispatcher(PlayerControlDispatcher())
Where playerView is an instance of com.google.android.exoplayer2.ui.PlayerView which we declare in our layout file.
Kotlin 2020 solution approach UPDATE
Events such as changes in state and playback errors are reported to registered Player.EventListener instances.
Player.EventListener has empty default methods, so you only need to implement the methods you’re interested in.
First your class, say your activity, has to conform to the Player.EventListener interface.
Then you override the onIsPlayingChanged method, on the class. Outside onCreate method...
Add the listener to your player instance:
// Adding player listener for tracking events
player?.addListener(this)
You can check if the player is playing (i.e. the position is advancing) with Player.isPlaying:
//Listening to player events
override fun onIsPlayingChanged(isPlaying: Boolean){
if (isPlaying) {
// Active playback.
} else {
// Not playing because playback is paused, ended, suppressed, or the player
// is buffering, stopped or failed. Check player.getPlaybackState,
// player.getPlayWhenReady, player.getPlaybackError and
// player.getPlaybackSuppressionReason for details.
}
}
That's it. Very simple.
You can use exoplayer.getPlayWhenReady() to check whether the player is currently in a pause state or playing state.
I think the callback:
fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int)
From the Player.Listener
With version 2.16.1, I use this code:
exoPlayer.addListener(object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
if (isPlaying){
videoIsPlaying()
}
}
})
Please try below code snipped. The player listener(onPlayerStateChanged) isn't good to observe play / pause action its called multiple time and also invoke while player configuring.
videoView.setControlDispatcher(object : DefaultControlDispatcher() {
override fun dispatchSetPlayWhenReady(player: Player, playWhenReady: Boolean): Boolean {
if (playWhenReady)
// Tap on Play button
else
// Tap on Pause button
return super.dispatchSetPlayWhenReady(player, playWhenReady)
}
})
for kotlin
private fun ExoPlayer.isPlaying() =
playbackState == Player.STATE_READY && playWhenReady