I am new to Android development and I am creating a Music Player app. I am done with the logical part. Now I am focusing on the appearance of the app. One of the things I want to do is to highlight a row when the corresponding 'Play' button in the row is clicked.
Desired Effect: When Play button of a row is clicked the row gets highlighted (Background color changes) and simultaneously the background of the last clicked row gets reset.
Attempt: I tried storing the previously selected View and make required changes in the current and previous views.
Following is the code I wrote in my custom Adapter for the ListView:
(Relevant code is written in the onClickListener() of the buttons)
package com.example.mediaplayer;
import android.app.Activity;
import android.content.ContentUris;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MusicAdapter extends ArrayAdapter<Music> {
private MediaPlayer mp;
private ArrayList<Integer> Lengths = new ArrayList<>();
private int mCurrentPosition = 0;
private LinearLayout mpreviousView = null;
private LinearLayout mitemView = null;
private IAdapterToFragment listener;
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
releaseMediaPlayer();
Lengths.set(mCurrentPosition, 0);
mitemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
}
};
public interface IAdapterToFragment {
void onSuccess(String songName);
}
public MusicAdapter(Activity context, ArrayList<Music> songs, IAdapterToFragment listener) {
super(context, 0, songs);
for(int i = 0; i < songs.size(); i ++) {
Lengths.add(0);
}
this.listener = listener;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
mpreviousView = mitemView;
View musicItemView = convertView;
if(musicItemView == null) {
musicItemView = LayoutInflater.from(getContext()).inflate(
R.layout.music_item, parent, false);
}
Music currentSong = getItem(position);
LinearLayout itemView = musicItemView.findViewById(R.id.item);
mitemView = itemView;
TextView songnameView = musicItemView.findViewById(R.id.song_name);
songnameView.setText(currentSong.getMusicName());
Button stop = (Button) musicItemView.findViewById(R.id.stop_button);
Button pause = (Button) musicItemView.findViewById(R.id.pause_button);
Button play = (Button) musicItemView.findViewById(R.id.play_button);
play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
releaseMediaPlayer();
if(listener != null)
listener.onSuccess(currentSong.getMusicName());
mCurrentPosition = position;
itemView.setBackgroundColor(Color.parseColor("#FAA185"));
long songID = currentSong.getMusicResourceId();
Uri uri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
songID);
mp = MediaPlayer.create(getContext(), uri);
mp.start();
mp.seekTo(Lengths.get(position));
mp.setOnCompletionListener(mCompletionListener);
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null)
listener.onSuccess("Play another song!");
releaseMediaPlayer();
itemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
Lengths.set(position, 0);
}
});
pause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int currentPosition = 0;
if(mp != null) {
currentPosition = mp.getCurrentPosition();
mp.stop();
Lengths.set(position, currentPosition);
releaseMediaPlayer();
// mp.setOnCompletionListener(mCompletionListener);
}
}
});
return musicItemView;
}
private void releaseMediaPlayer() {
if (mp != null) {
mp.release();
mp = null;
if(mpreviousView != null)
mpreviousView.setBackgroundColor(Color.parseColor("#FDBCA8"));
// mp.abandonAudioFocus(mOnAudioFocusChangeListener);
}
}
}
This however doesn't work because ListView recycles the views. So I am not accessing a distinct row, rather, I am making changes to many rows simultaneously.
Questions:
Is there a way I can uniquely access a row in a ListView in the adapter class itself?
Is there an easier way to achieve the desired effect?
Thank you.
EDIT:
After researching a lot and trying several methods from related questions, I still haven't figured out a way to get the desired effect. All the methods I tried result in multiple rows getting highlighted when one button is clicked, again, due to recycling of views. If you are looking for an alternate solution, you can either:
(Not Optimal) Replace ListView with some layout that doesn't recycle views. This way the exactly one item gets highlighted and remains highlighted even when you scroll past it.
Remove all types of buttons from the list, create a list item selector and set it as the background for you list_item. Follow the steps mentioned here: Reset background color in a ListView. This is the one I am using for my app now.