Android mediaplayer next song onButton Click - java

Button btnPlayPause, btnNext, btnPrevious;
Bundle b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song);
btnPlayPause = (Button) findViewById(R.id.btnPlayPause);
btnNext = (Button) findViewById(R.id.btnNext);
btnPrevious = (Button) findViewById(R.id.btnPrevious);
Intent currSong = getIntent();
b = currSong.getExtras();
btnPlayPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
btnPlayPause.setText("Play");
} else {
mediaPlayer.start();
btnPlayPause.setText("Stop");
}
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
btnPlayPause.setText("Play");
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
int songIndex = (int) b.get("songIndex");
#Override
public void onClick(View v) {
if (songIndex < songList.size() - 1) {
songIndex = songIndex + 1;
Toast.makeText(getApplicationContext(), "You Clicked " + songIndex , Toast.LENGTH_SHORT).show();
try {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.setDataSource(songList.get(songIndex).getData());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}else{
songIndex=0;
}
}
});
btnPrevious.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (songIndex > 0){
songIndex = songIndex-1;
Toast.makeText(getApplicationContext(), "You Clicked " + songIndex , Toast.LENGTH_SHORT).show();
try {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.setDataSource(songList.get(songIndex).getData());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}else {
songIndex = songList.size() - 1;
}
}
});
}
}
So when i click on the next button, it plays the second song, but at the end of my songlist it skips the first song from the list stored in [0] and on second click it goes to [1] so there is always one song not playing.
How can i solve this or is there an easier way too go to the next song?
Thanks,
-Vince
EDIT;
Problem 2; when i choose a song, lets say with position 37, and i click on previous it goes to 36, but if i then click on next it goes to 38, so it skips the song i played first.
EDIT 2 ;
Ok problems still persists, but i found out that when i click a few times on previous btn let's say i start from position 25 and go to 15 with the previous btn, and when i then click on next again it just starts to count from 25. How can i solve this? Thanks in advance, - vince

Ok, you have several problems here:
i found out that when i click a few times on previous btn let's say i start from position 25 and go to 15 with the previous btn, and when i then click on next again it just starts to count from 25
In PlayNext's first line, you reassign songIndex to the original songIndex passed to the activity. PlayPrevious uses another songIndex that I can't see where is defined. If you had followed Android guidelines to always prefix with an "m" the class properties vs local variables, you'd easily have realised it.
So when i click on the next button, it plays the second song, but at the end of my songlist it skips the first song from the list stored in [0] and on second click it goes to [1]
The edge cases where user plays the next after the last song, or the previous after the first are incorrectly coded. In those cases you correctly update songIndex, but do not call play.
Besides the problems, what you should do is to rework your code a little using functions, to avoid repeating functionality. That is always prone to these kind of errors. I'd suggest something like this:
int mCurrentIndex; // always prefix class properties with an "m"
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song);
Button btnPlayPause = (Button) findViewById(R.id.btnPlayPause),
btnNext = (Button) findViewById(R.id.btnNext),
btnPrevious = (Button) findViewById(R.id.btnPrevious);
Intent currSong = getIntent();
Bundle b = currSong.getExtras();
// load initial index only once
mCurrentIndex = (int) b.get("songIndex");
btnPrevious.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCurrentIndex = mCurrentIndex > 0 ? mCurrentIndex - 1 : mSongList.size() - 1;
playSongNumber(mCurrentIndex);
}
}
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCurrentIndex++;
mCurrentIndex %= mSongList.size();
playSongNumber(mCurrentIndex);
}
}
}
private void playSongNumber(int index) {
try {
mMediaPlayer.stop();
mMediaPlayer.reset();
mMediaPlayer.setDataSource(mSongList.get(index).getData());
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
slightly cleaner, isn't it?

Related

Is there a way to set adapter position of view holder of recycler view programmatically?

Just like a view holder has the method getAdapterPosition(), I want to write my own setAdapterPosition() for the view holder(which doesn't exist).
What am I working on?
Currently, I am working on a project wherein I have to list 10 songs in the form of a recycler view and then play them, if any particular song is clicked. Each list item contains the song name, a seek bar and a play button
I have implemented this part, by adding all the media player contros inside the adapter class.
What do I want?
Currently, this model used mediaPlayer.setLooping(true) so that as soon as a song finished, it kept looping till some other song is clicked for playing.
Now I want to extend this model to an "autoplay" version so that as soon as a song is finished, the next song is played
What is the problem?
The seekBar progress and playButton image transition to a pauseButton image were happening with the call
viewHolder.seekBar.setProgress(...)
viewHolder.playButton.setImageDrawable(...)
Since this was happening on the
viewHolder.itemView.setOnClickListener(...)
as soon as a new song was clicked, the seekBar and playButton image were being updated.
Now, when the song is completed, I don't want the user to click on the next song to play it. I want it to be autoplayed, but I am unable to understand, how do I change myViewHolder position accordingly.
Suppose Song 0 has finished playing and Song 1 has started playing, viewHolder.getAdapterPosition() still returns 0 instead of 1. Hence the seekBar & playButton of song 0 is being updated and not of song 1.
I want to be able to do something like this
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
int nextSongPosition, currentSongPosition;
currentSongPosition = viewHolder.getAdapterPosition();
if(currentSongPosition==(songs.size()-1)){
nextSongPosition = 0;
//do some miracle so that viewHolder.getAdapterPosition() now shows 0 instead of currentSongPosition
}else{
nextSongPosition = currentSongPosition + 1;
//do some miracle so that viewHolder.getAdapterPosition() now shows nextSongPosition instead of the currentSongPosition;
}
}
});
As clear from the question statement, I want to implement something similar to a setAdapterPosition() which doesn't exist.
EDIT 1
onBindViewHolder Code:
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, int i) {
Song song = songs.get(i);
viewHolder.itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
audioManager = (AudioManager) Objects.requireNonNull(context).getSystemService(Context.AUDIO_SERVICE);
if(mediaPlayer.isPlaying()){
pauseMediaPlayer(viewHolder);
}else{
StorageReference storageRef = FirebaseStorage.getInstance().getReference("Songs");
StorageReference dateRef = storageRef.child(song.getStoredAs());
dateRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
try {
mediaPlayer.setDataSource(uri.toString());
mediaPlayer.prepare();
viewHolder.seekBar.setMax(mediaPlayer.getDuration() / 1000);
mSeekbarUpdateHandler = new Handler();
mUpdateSeekbar = new Runnable() {
#Override
public void run() {
if (viewHolder.seekBar != null && mediaPlayer != null) {
try{
viewHolder.seekBar.setProgress(mediaPlayer.getCurrentPosition() / 1000);
mSeekbarUpdateHandler.postDelayed(this, 50);
} catch(IllegalStateException e){
Log.i("Exception",e.toString());
}
}
}
};
viewHolder.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser && mediaPlayer != null)
mediaPlayer.seekTo( progress * 1000);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
startMediaPlayer(viewHolder);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
Log.i("Song Loading Error", exception.toString());
}
});
}
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
int nextSongPosition, currentSongPosition;
currentSongPosition = viewHolder.getAdapterPosition();
if(currentSongPosition==(songs.size()-1)){
nextSongPosition = 0;
//do some miracle so that viewHolder.getAdapterPosition() now shows 0 instead of currentSongPosition
}else{
nextSongPosition = currentSongPosition + 1;
//do some miracle so that viewHolder.getAdapterPosition() now shows nextSongPosition instead of the currentSongPosition;
}
}
});
}
pauseMediaPlayer(..) & startMediaPlayer(..) Code:
private void pauseMediaPlayer(ViewHolder viewHolder) {
int result = audioManager.requestAudioFocus(this, AudioManager.USE_DEFAULT_STREAM_TYPE, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
isSongPlaying = false;
viewHolder.playButton.setImageResource(R.drawable.play_button);
if (mediaPlayer != null) {
mediaPlayer.pause();
}
}
}
private void startMediaPlayer(ViewHolder viewHolder) {
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
isSongPlaying = true;
viewHolder.playButton.setImageResource(R.drawable.pause_button);
if (mediaPlayer != null) {
//mediaPlayer.setLooping(true);
mediaPlayer.start();
}
mSeekbarUpdateHandler.postDelayed(mUpdateSeekbar, 0);
}
}

My algorithm never met the requirements to start an Activity?

I created an Android game, but it isn't working how it should.
Main idea
User clicks CheckedTextView three times and after the third click, a second Activity is started.
Problem
Second Activity isn't starting.
]
Code with an algorithm:
public class StartOfTheGame extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.startofthegame);
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
final CheckedTextView checkedTextView = findViewById(R.id.checked_textview);
checkedTextView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
String[] seasons = {"1", "2", "3", "4"};
int n = (int)Math.floor(Math.random() * seasons.length);
checkedTextView.toggle();
int a = 0;
if(checkedTextView.isChecked()) {
checkedTextView.setChecked(false);
checkedTextView.setText(seasons[n]);
a++;
}
if (a == 3){
try {
Intent intent = new Intent(StartOfTheGame.this, SecondStageOfTheGame.class);
startActivity(intent);
finish();
} catch (Exception e) {
}
}
}
});
a is a local variable. So, everytime you click, a is first set to 0 at int a = 0;
Try the code below:
checkedTextView.setOnClickListener(new View.OnClickListener(){
private int a = 0; // Add this here
#Override
public void onClick(View v) {
...
// int a = 0; // Remove this
...
if (a == 3){
try {
Intent intent = new Intent(StartOfTheGame.this, SecondStageOfTheGame.class);
startActivity(intent);
finish();
} catch (Exception e) {
}
}
}
}

Button.setOnClickListener doesn't work at all

I am programming a metronome for Android and use a thread for playing the sound in the rythm the user says but somehow my setOnClickListener won't work. The button doesn't even click when clicked. What is wrong with my code?
startb = (Button) findViewById(R.id.start_but);
stopb = (Button) findViewById(R.id.stop_but);
startb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
running = true;
bpm_val = findViewById(R.id.metr_input);
value = bpm_val.getText().toString();
int beat = Integer.parseInt(value);
Soundplay(beat / 60); //The beats per second
}
});
stopb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
running = false;
}
});
}
public void Soundplay(final long bps) {
startb = (Button) findViewById(R.id.start_but);
stopb = (Button) findViewById(R.id.stop_but);
running = true;
new Thread() {
#Override
public void run() {
super.run();
MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.metronome_klack);
int i = 0;
while (running) {
if(i == 1000) {
mp.start();
i = 0;
}
try {
sleep(bps);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
You have initialized the button twice in your code.
First in onCreate() method and second time in Soundplay(final long bps) method. You can remove the initialization from Soundplay method. As it seems that button is initialized on its click listner itself. I think that's the issue.
public void Soundplay(final long bps) {
//Remove this portion
**startb = (Button) findViewById(R.id.start_but);**
**stopb = (Button) findViewById(R.id.stop_but);**
...
}
Hope it helps.

Android- Error Message

I have been recently having an error when compiling my android code onto an emulator. The game is that when you click a button, it gives you a math question displayed on a textView, and user types their answer (in numbers) and clicks the button 'check' When I click that button, it always returns false.
Anyone knows how to fix this?
Java Class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
mathQuestion = findViewById(R.id.magic_textview);
redCircle = findViewById(R.id.math_ball);
yellowbox = findViewById(R.id.yellow_box);
yellowboxY = 1550f - 130f;
yellowbox.setY(yellowboxY);
yellowboxX = 472f;
yellowbox.setX(yellowboxX);
type_answer = findViewById(R.id.type_answer);
Button checkButton = findViewById(R.id.check_button);
checkButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(redCircleX == yellowboxX && redCircleY == yellowboxY){
mathQuestion.setText("What is "+math_int1+" + "+math_int2+" ?");
math_int1 = r.nextInt(20);
math_int2 = r.nextInt(20)+1;
string_math_int1 = String.valueOf(math_int1);
string_math_int2 = String.valueOf(math_int2);
Button checkAnswer = findViewById(R.id.check_answer);
checkAnswer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Error? Always returning false?
if (type_answer.getText().toString().contains (Integer.toString( math_int1 + math_int2))) {
Toast t = Toast.makeText(GameActivity.this, "Success!", Toast.LENGTH_SHORT);
t.show();
} else {
Toast t2= Toast.makeText(GameActivity.this, type_answer.getText().toString(), Toast.LENGTH_SHORT);
t2.show();
}
}
});
}else{
Toast.makeText(GameActivity.this, "Incorrect Or Error", Toast.LENGTH_SHORT).show();
}
}
});
Button upButton = findViewById(R.id.up_button);
upButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
moveUp();
}
});
Button downButton = findViewById(R.id.down_button);
downButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
moveDown();
}
});
Button leftButton = findViewById(R.id.left_button);
leftButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
moveLeft();
}
});
Button rightButton = findViewById(R.id.right_button);
rightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
moveRight();
}
});
Button resetCircleXY = findViewById(R.id.reset_button);
resetCircleXY.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
initCircleXY();
Toast.makeText(GameActivity.this, "Reset Ball's Position", Toast.LENGTH_SHORT).show();
}
});
upButton.performClick();
leftButton.performClick();
redCircleY = 1550f;
redCircle.setY(redCircleY);
redCircleX = 472f;
redCircle.setX(redCircleX);
}
private void moveUp(){
redCircleY -= ballMoveDis;
redCircle.setY(redCircleY);
}
private void moveDown(){
redCircleY += ballMoveDis;
redCircle.setY(redCircleY);
}
private void moveLeft(){
redCircleX += ballMoveDis;
redCircle.setX(redCircleX);
}
private void moveRight(){
redCircleX -= ballMoveDis;
redCircle.setX(redCircleX);
}
private void initCircleXY(){
redCircleY = 1550f;
redCircle.setY(redCircleY);
redCircleX = 472f;
redCircle.setX(redCircleX);
}
}
Help is greatly appreciated, Thanks
First mistake
string_math_int1 = String.valueOf(math_int1);
string_math_int2 = String.valueOf(math_int1); // this should be math_int2
BUT consider adding two strings
string_math_int1 + string_math_int2)
"10" + "20"
equals
"1020" not "30"
Maybe
if (type_answer.getText().toString().equals(String.valueOf (math_int1 + math_int2) {
Answer to newly formatted question:
Your issue has to do with comparing two strings when you want to check their int values. You could try using Integer.parseInt() on your EditText's entry. Just be aware you will need to do a try on it to catch an exception in the case of your EditText having any non numeric characters.
Answer to previous question about crash before edit:
Your crash isn't with your EditText. It is this line:
Toast.makeText(GameActivity.this,math_int1 + math_int2 , Toast.LENGTH_SHORT).show();
By passing it an int value, it is attempting to look up a string with that id. If your intent is to display the sum of those ints, it should look something like:
Toast.makeText(GameActivity.this, String.valueOf(math_int1 + math_int2), Toast.LENGTH_SHORT).show();

How to play the next song in an array?

For an assignment I am trying to play songs from an array using media player. The first song in the array plays fine, but the next, and last track buttons are where my issue is. Could anyone suggest a way of playing the next/last song from my music array?
None relevant code not included.
// Arrays of sound files
private int[] audioFileArrayChill = {R.raw.vanilla_summer, R.raw.lifeline, R.raw.remember_the_mountain_bed};`
// Listen for the end of the track
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
for (int x = 1; x <= audioArray.length; x++) {
currentIndex++;
// Play next song in array
mp.selectTrack(audioArray[x]);
mp.start();
}
}
});
// Assigning onClickListener to last track button
lastTrack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mediaPlayer.reset();
mediaPlayer.selectTrack(audioArray[currentIndex - 1]);
try {
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
Log.e("Error", "ERROR");
}
}
});
// Assigning onClickListener to next track button
nextTrack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mediaPlayer.reset();
mediaPlayer.selectTrack(audioArray[currentIndex + 1]);
try {
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
Log.e("Error", "ERROR");
}
}
});
use below code for next button click
nextTrack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp.stop();
mp.reset();
mp.setDataSource(audioArray[currentIndex + 1]);
mp.prepare();
mp.start();
}

Categories