I'm trying to indicate what song is playable at the moment and change its TextView colour to blue. At the moment it works when I click the song, but when the current song finishes and MediaPlayer start the next song - I don't know how to indicate that to RecyclerView class.
I have a music adapter class that extends RecyclerView and I use static ArrayList variable musicFiles - declared and set in MainActivity:
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.example.musicapp.Activities.PlayerActivity;
import com.example.musicapp.R;
import com.google.android.material.snackbar.Snackbar;
import java.io.File;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.ArrayList;
import static com.example.musicapp.Activities.MainActivity.musicFiles;
import static com.example.musicapp.Activities.PlayerActivity.mediaPlayer;
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.MyViewHolder>
{
private final Context mContext;
private int row_index = -1;
public MusicAdapter(Context mContext)
{
this.mContext = mContext;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(mContext).inflate(R.layout.music_items, parent, false);
return new MyViewHolder(view);
}
public static boolean isPathValid(String path)
{
try
{
Paths.get(path);
}
catch (InvalidPathException ex)
{
return false;
}
return true;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)
{
String file_name_text = musicFiles.get(position).getTitle();
String album_name_text = musicFiles.get(position).getAlbum();
if (file_name_text.length() > 26)
file_name_text = file_name_text.substring(0, 26) + "...";
if (album_name_text.length() > 20)
album_name_text = album_name_text.substring(0, 20) + "...";
holder.file_name.setText(file_name_text);
holder.album_name.setText(album_name_text);
byte[] image = null;
if (musicFiles.get(position).getPath() != null && isPathValid(musicFiles.get(position).getPath()))
image = getAlbumArt(musicFiles.get(position).getPath());
if (mediaPlayer != null && mediaPlayer.isPlaying() && mediaPlayer.getDuration() == Integer.parseInt(musicFiles.get(position).getDuration()))
{
row_index = position;
}
if (image != null)
{
Glide.with(mContext).asBitmap()
.load(image)
.into(holder.album_art);
}
else
{
Glide.with(mContext)
.load(R.drawable.musicimage)
.into(holder.album_art);
}
holder.itemView.setOnClickListener(v ->
{
row_index = position;
notifyDataSetChanged();
Intent intent = new Intent(mContext, PlayerActivity.class);
intent.putExtra("position", position);
mContext.startActivity(intent);
});
if (row_index == position)
{
holder.file_name.setTextColor(Color.parseColor("#008B8B"));
holder.album_name.setTextColor(Color.parseColor("#008B8B"));
}
else
{
holder.file_name.setTextColor(ContextCompat.getColor(mContext.getApplicationContext(), R.color.black));
holder.album_name.setTextColor(ContextCompat.getColor(mContext.getApplicationContext(), R.color.black));
}
holder.menuMore.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(final View v)
{
PopupMenu popupMenu = new PopupMenu(mContext, v);
popupMenu.getMenuInflater().inflate(R.menu.popup, popupMenu.getMenu());
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener()
{
@Override
public boolean onMenuItemClick(MenuItem item)
{
if (item.getItemId() == R.id.delete)
deleteFile(position, v);
return true;
}
});
}
});
}
public void deleteFile(int position, View view)
{
Uri contentUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
Long.parseLong(musicFiles.get(position).getId()));
File file = new File(musicFiles.get(position).getPath());
boolean deleted = file.delete(); // delete file
if (deleted)
{
mContext.getContentResolver().delete(contentUri, null, null);
musicFiles.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, musicFiles.size());
Snackbar.make(view, "File deleted", Snackbar.LENGTH_LONG).show();
}
// else is when the file is in the sd card
else
Snackbar.make(view, "Can't be deleted!", Snackbar.LENGTH_LONG).show();
}
@Override
public int getItemCount()
{
return musicFiles.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder
{
TextView file_name, album_name;
ImageView album_art, menuMore;
public MyViewHolder(@NonNull View itemView)
{
super(itemView);
file_name = itemView.findViewById(R.id.music_file_name);
album_name = itemView.findViewById(R.id.album_file_name);
album_art = itemView.findViewById(R.id.music_img);
menuMore = itemView.findViewById(R.id.menuMore);
}
}
private byte[] getAlbumArt(String uri)
{
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri);
byte[] art = retriever.getEmbeddedPicture();
retriever.release();
return art;
}
}
In that code - onBindViewHolder() method part changes the TextView of the clicked song:
holder.itemView.setOnClickListener(v ->
{
row_index = position;
notifyDataSetChanged();
Intent intent = new Intent(mContext, PlayerActivity.class);
intent.putExtra("position", position);
mContext.startActivity(intent);
});
if (row_index == position)
{
holder.file_name.setTextColor(Color.parseColor("#008B8B"));
holder.album_name.setTextColor(Color.parseColor("#008B8B"));
}
else
{
holder.file_name.setTextColor(ContextCompat.getColor(mContext.getApplicationContext(), R.color.black));
holder.album_name.setTextColor(ContextCompat.getColor(mContext.getApplicationContext(), R.color.black));
}
But then in my PlayerActivity class, I have buttons for the next song and the previous song and when I switch the song and return to MusicAdapter - I don't know how to change the TextView colour of the current song and return to the previous one. Here is the PlayerActivity code:
package com.example.musicapp.Activities;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.example.musicapp.Musics.MusicFile;
import com.example.musicapp.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
import java.util.Random;
import static com.example.musicapp.Activities.MainActivity.musicFiles;
import static com.example.musicapp.Activities.MainActivity.repeatBoolean;
import static com.example.musicapp.Activities.MainActivity.shuffleBoolean;
public class PlayerActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener
{
TextView song_name, artist_name, duration_played, duration_total;
ImageView cover_art, nextBtn, prevBtn, backBtn, shuffleBtn, repeatBtn;
FloatingActionButton playPauseBtn;
SeekBar seekBar;
int position = -1;
ArrayList<MusicFile> listSongs = new ArrayList<>();
static Uri uri;
public static MediaPlayer mediaPlayer;
private Thread playThread, prevThread, nextThread;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
initViews();
getIntentMethod();
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
mediaPlayer.setOnCompletionListener(this);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (mediaPlayer != null && fromUser)
mediaPlayer.seekTo(progress * 1000);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
duration_played.setText(formattedTime(mCurrentPosition));
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
shuffleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
if (shuffleBoolean)
{
shuffleBoolean = false;
shuffleBtn.setImageResource(R.drawable.ic_shuffle_off);
}
else
{
shuffleBoolean = true;
shuffleBtn.setImageResource(R.drawable.ic_shuffle_on);
}
}
});
repeatBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
if (repeatBoolean)
{
repeatBoolean = false;
repeatBtn.setImageResource(R.drawable.ic_repeat_off);
}
else
{
repeatBoolean = true;
repeatBtn.setImageResource(R.drawable.ic_repeat_on);
}
}
});
}
@Override
protected void onResume()
{
playThreadBtn();
nextThreadBtn();
prevThreadBtn();
super.onResume();
}
private void prevThreadBtn()
{
prevThread = new Thread()
{
@Override
public void run()
{
super.run();
prevBtn.setOnClickListener(v -> prevBtnClicked());
}
};
prevThread.start();
}
private void prevBtnClicked()
{
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
mediaPlayer.release();
if (shuffleBoolean && !repeatBoolean)
position = getRandom(listSongs.size() - 1);
else if (!shuffleBoolean && !repeatBoolean)
position = ((position - 1) < 0 ? (listSongs.size() - 1) : (position - 1));
// else position will be the same ...
uri = Uri.parse(listSongs.get(position).getPath());
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
metaData(uri);
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
mediaPlayer.setOnCompletionListener(this);
playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
mediaPlayer.start();
}
else
{
mediaPlayer.stop();
mediaPlayer.release();
if (shuffleBoolean && !repeatBoolean)
position = getRandom(listSongs.size() - 1);
else if (!shuffleBoolean && !repeatBoolean)
position = ((position - 1) < 0 ? (listSongs.size() - 1) : (position - 1));
// else position will be the same ...
uri = Uri.parse(listSongs.get(position).getPath());
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
metaData(uri);
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
mediaPlayer.setOnCompletionListener(this);
playPauseBtn.setBackgroundResource(R.drawable.ic_play_arrow);
}
}
private void nextThreadBtn()
{
nextThread = new Thread()
{
@Override
public void run()
{
super.run();
nextBtn.setOnClickListener(v -> nextBtnClicked());
}
};
nextThread.start();
}
private void nextBtnClicked()
{
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
mediaPlayer.release();
if (shuffleBoolean && !repeatBoolean)
position = getRandom(listSongs.size() - 1);
else if (!shuffleBoolean && !repeatBoolean)
position = ((position + 1) > (listSongs.size() - 1) ? 0 : (position + 1));
// else position will be the same ...
uri = Uri.parse(listSongs.get(position).getPath());
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
metaData(uri);
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
mediaPlayer.setOnCompletionListener(this);
playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
mediaPlayer.start();
}
else
{
mediaPlayer.stop();
mediaPlayer.release();
if (shuffleBoolean && !repeatBoolean)
position = getRandom(listSongs.size() - 1);
else if (!shuffleBoolean && !repeatBoolean)
position = ((position + 1) > (listSongs.size() - 1) ? 0 : (position + 1));
// else position will be the same ...
position = ((position + 1) > (listSongs.size() - 1) ? 0 : (position + 1));
uri = Uri.parse(listSongs.get(position).getPath());
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
metaData(uri);
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
mediaPlayer.setOnCompletionListener(this);
playPauseBtn.setBackgroundResource(R.drawable.ic_play_arrow);
}
}
private int getRandom(int num)
{
Random random = new Random();
return random.nextInt(num + 1);
}
private void playThreadBtn()
{
playThread = new Thread()
{
@Override
public void run()
{
super.run();
playPauseBtn.setOnClickListener(v -> playPauseBtnClicked());
}
};
playThread.start();
}
private void playPauseBtnClicked()
{
if (mediaPlayer.isPlaying())
{
playPauseBtn.setImageResource(R.drawable.ic_play_arrow);
mediaPlayer.pause();
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
}
else
{
playPauseBtn.setImageResource(R.drawable.ic_pause);
mediaPlayer.start();
seekBar.setMax(mediaPlayer.getDuration() / 1000);
PlayerActivity.this.runOnUiThread(new Runnable()
{
@Override
public void run()
{
if (mediaPlayer != null)
{
int mCurrentPosition = mediaPlayer.getCurrentPosition() / 1000;
seekBar.setProgress(mCurrentPosition);
}
new Handler(Looper.getMainLooper()).postDelayed(this, 10);
}
});
}
}
public static String formattedTime(int mCurrentPosition)
{
String totalOut;
String totalNew;
String seconds = String.valueOf(mCurrentPosition % 60);
String minutes = String.valueOf(mCurrentPosition / 60);
totalOut = minutes + ":" + seconds;
totalNew = minutes + ":" + "0" + seconds;
if (seconds.length() == 1)
return totalNew;
else
return totalOut;
}
private void getIntentMethod()
{
position = getIntent().getIntExtra("position", -1);
listSongs = musicFiles;
if (listSongs != null)
{
playPauseBtn.setImageResource(R.drawable.ic_pause);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null)
{
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
seekBar.setMax(mediaPlayer.getDuration() / 1000);
metaData(uri);
}
private void initViews()
{
song_name = findViewById(R.id.song_name);
artist_name = findViewById(R.id.song_artist);
duration_played = findViewById(R.id.durationPlayed);
duration_total = findViewById(R.id.duration);
cover_art = findViewById(R.id.cover_art);
nextBtn = findViewById(R.id.id_next);
prevBtn = findViewById(R.id.id_prev);
backBtn = findViewById(R.id.back_btn);
shuffleBtn = findViewById(R.id.id_shuffle);
repeatBtn = findViewById(R.id.id_repeat);
playPauseBtn = findViewById(R.id.play_pause);
seekBar = findViewById(R.id.seekBard);
}
private void metaData(Uri uri)
{
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri.toString());
int durationTotal = Integer.parseInt(listSongs.get(position).getDuration()) / 1000;
duration_total.setText(formattedTime(durationTotal));
byte[] art = retriever.getEmbeddedPicture();
if (art != null)
{
Glide.with(this)
.asBitmap()
.load(art)
.into(cover_art);
}
else
{
Glide.with(this)
.asBitmap()
.load(R.drawable.musicimage)
.into(cover_art);
}
}
@Override
public void onCompletion(MediaPlayer mp)
{
nextBtnClicked();
if (mediaPlayer != null)
{
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(this);
}
}
}