Preload MediaPlayer in RecyclerView Adapter? - java

I have an RecylcerView with multiple imges in my app.
If the images are getting loaded in the onBindViewholder it should also prepare the MediaPlayer.
When the user clicks the button it should start the MediaPlayer.
Normaly I would just create the MediaPlayer when the user clicks the button but in my case I'm playing the sound from an URL so it takes some time for the sound to play when the user has bad internet.
So I try to create and prepare the MediaPlayer as soon as the RecyclerView Item gets created and start it when the user clicks the button.
Is this the right way to do it? Because now I have the problem that I have multiple MediaPlayers at once and I don't know how I can stop and clear all MediaPlayers when the user clicks a "stop" button.
Here is the onBindViewHolder method from my RecyclerView Adapter:
#Override
public void onBindViewHolder(#NonNull final SoundViewHolder holder, int position) {
SoundItems currentItem = mSoundItems.get(position);
final String imageUrl = currentItem.getImageResource();
final String mp3Path = currentItem.getMp3Path();
Glide.with(mContext)
.load(imageUrl)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.into(holder.itemImageView);
final MediaPlayer mediaPlayer;
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(mp3Path);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
holder.itemImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mediaPlayer.start();
}
});
What is the best way to preload the sounds so that the sound gets played instantly when the user clicks button and how to stop all MediaPlayers at once?
P.S
The sounds are between 3 and 30 seconds long.

You can use my code :
Instead of using Exoplayer you can use MediaPlayer if you want..
But with this code files will be prefetched too.
https://github.com/NehaKushwah993/InstagramVideoFeedClone
Let me know if it works.

Related

Android Studio Online Radio app(java) from API [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have to do a project for univeristy in android studio a radio online who take elements from API(java language). For first i've done the adapterview(with a list) and take elements from api, My question is how can i implement media player in my code to play the stream from api(i have the code for media player but works only for one link and i dont know how to implement to this project.
I have put my code there:https://textuploader.com/tsu8j
https://i.stack.imgur.com/Cfwph.png
Please see onPlayClick which is called on the play button, right now I always change the URL to the radio station which is clicked on just to show you how can you change the URL for media to be played in mediaplayer.
YOu can yourself think of logic to show the `pause' button and updating them according to the song is played.
Right now this snippet is to show you how you can changes the ongoing radio to different when you clicked upon that.
getAdapterPosition(): I am taking leverage of this to know which row's Play button is clicked so that accordingly I can switch to that radio station.
mediaPlayer.prepareAsync(): so that I don't block the main thread.
setOnPreparedListener because we want to start our mediaPlayer when it is done prepared and as we have done it asynchronously we have to listen for the callback to know when to start our media player.
setOnErrorListener to know if there is some error while playing some media, this was helpful as in your case out of 10 stations only 5 or 6 are working and others are throwing error and this callback actually helped me to know why exactly media was not played.
stopPlaying There is mediaPlayer.stop(); and mediaPlayer.reset(); this are to make sure that before new media data is set using mediaPlayer.setDataSource already playing media is stopped and the data is reset.
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
// creating a variable for array list and context.
private ArrayList<RadioStation> radioStationArrayList;
private MediaPlayer mediaPlayer;
// creating a constructor for our variables.
public Adapter(ArrayList<RadioStation> radioStationArrayList, Context context) {
this.radioStationArrayList = radioStationArrayList;
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
#NonNull
#Override
public Adapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// below line is to inflate our layout.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_rv_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull Adapter.ViewHolder holder, int position) {
// setting data to our views of recycler view.
RadioStation modal = radioStationArrayList.get(position);
holder.name.setText(modal.getName());
Picasso.get().load(modal.getFavicon()).into(holder.favicon);
}
#Override
public int getItemCount() {
// returning the size of array list.
return radioStationArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
// creating variables for our views.
private TextView name;
private ImageView favicon;
private Button play;
public ViewHolder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.idName);
favicon = itemView.findViewById(R.id.idImg);
play = itemView.findViewById(R.id.play);
play.setOnClickListener(view -> onPlayClick());
}
public void onPlayClick() {
stopPlaying();
startPlaying();
}
private void startPlaying() {
try {
mediaPlayer.setDataSource(radioStationArrayList.get(getAdapterPosition()).getUrl_resolved());
mediaPlayer.setOnPreparedListener(mp -> {
mediaPlayer.start();
Log.v("DINKAR", "Started");
});
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
Log.e("DINKAR", "Error");
return false;
});
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e("DINKAR", "failed");
}
}
private void stopPlaying() {
mediaPlayer.stop();
mediaPlayer.reset();
}
}
}
Note: many of the radio stations are having issues MediaPlayer were not able to play those.
I used https://textuploader.com/tsu8j to get your adapter class code and using your screenshot of the app created layout XML file on my own so that I can run the app to test it out before giving you any snippet

mediaPlayer.release() crashes my app java

I have a project where I added a MediaPlayer in a custom Array Adapter and I make it take the Resource ID of the audio file from the Array List the problem is that I want to release the media player after the audio completes but every time I try to add release in OnCompletion and try to press a view while the media player plays a sound the app crashes .. I searched online and found a code but it gives me an error and I can't find the actual reason for such a crash.
that's the code for the on Click Listener and the Media player:
final MediaPlayer mediaPlayer = MediaPlayer.create(getContext(), currentWord.getVoiceResourceID());
// Wait for user's input by his click on the list's item to play the sound.
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
// Storing the return value of getVoiceResourceID() into mVoice.
// I think this line can be ignored so we call the method inside the creation of the Media Player.
// Creating our media player and put our track on it.
mediaPlayer.selectTrack(currentWord.getVoiceResourceID());
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mediaPlayer.release();
}
});
}
};
I hope I could fix that problem.

Changing the background color when audio is done

I'm new to java and i'm struggling with this for a long time. I'm making a soundboard and whenever a cardview is pressed i want it to play a sound and change the background color of the cardview for the duration of the audio. How can i make this happen? Playing the sound and changing the color are already working but i don't know how to set a duration or something. Can anyone help me out?
final MediaPlayer bingoMediaPlayer = MediaPlayer.create(this, R.raw.bingo);
final CardView bingo = (CardView) this.findViewById(R.id.play_bingo);
bingo.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
bingoMediaPlayer.start();
bingo.setCardBackgroundColor(Color.parseColor("#FF6F00"));
Toast.makeText(MainActivity.this,"kekkkk", Toast.LENGTH_SHORT).show();
}
});
Reset the color when the audio is completed. For this you could use the OnCompletionListener.
bingoMedia.setOnCompletionListener {
bingo.setCardBackgroundColor(Color.parseColor("your_default_color"))
}
You can find the original documentation here: MediaPlayer.OnCompletionListener

Android mediaplayer won't start after pause

I'm trying make a simple mediaplayer but the pause button doesn't work. When I click on the pause button it stops but when I click on play again it starts at the start again.
I don't know how to make one button where I can play/pause the button.
Code I currently have:
http://pastebin.com/wiDkzw5S
Thanks already!
You would need to save current position of media player and restart it later from that position using seekTo.
Something like:
int currentPos = 0;
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mediaPlayer.isPlaying()) {
currentPos = mediaPlayer.getCurrentPosition();
mediaPlayer.pause();
//change image to play
} else {
mediaPlayer.seekTo(currentPos);
mediaPlayer.start();
//again revert image to pause
}
}
});
Hope it helps.
This is running test and running code, you may use this for pause and resume the media player.
int length=0;
Button pause = (Button) findViewById(R.id.pause);
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
length=mediaPlayer.getCurrentPosition();
} else {
mediaPlayer.seekTo(length);
mediaPlayer.start();
}
}
});
I had a similar problem, but I couldn't get it to resume using the methods above.
I discovered my pauseAllSounds() function was pausing all MediaPlayer instances in my sound pool even if they weren't already playing. When that happened, it caused an error in each instance which wasn't playing which prevented that instance from playing again later. I discovered this after some time only by happening across the console output for my running process searching for the cause. It showed line after line of errors, revealing I was trying to pause from an invalid state.
// Make sure you test isPlaying() before pausing
public void pause() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
position = mediaPlayer.getCurrentPosition();
}
}
Once I added the test to only pause if it was already playing, everything worked.

Cancel asynctask launched with onClickListener in an Adapter created inside onPostExecute

This is my context: I have an activity which downloads a list of video and set them into an adapter. When user clicks on each item, application downloads and streams video in an external application.
So, let's see some code. Main activity has this:
new TvAsyncTask(getActivity(), gridView, progressBar).execute();
TvAsyncTask download video list and sets it like here:
protected void onPostExecute(ArrayList<VideoPreviewData> list) {
progressBar.setVisibility(View.INVISIBLE);
final TvListAdapter adapter = new TvListAdapter(activity.getApplicationContext(), R.layout.item_video_list, list);
videoGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
String videoUrl = adapter.getItem(position).getLink();
//Launch asyncTask to download video an load it into an external media player
new GetVideoAsyncTask(activity).execute(videoUrl);
}
});
if (videoGridView!=null) videoGridView.setAdapter(adapter);
}
GetVideoAsyncTask load video link and lauch an Intent in an external application to stream that video. In order to do this, during onLoading I set a ProgressDialog that shows to the user a loading message. After that loading is completed, intent is launched.
Problem
When ProgressDialog is shown and user click "back button" the dialog is cancelled but the asynctask continues to work. So when it finishes it launches intent.
I want to prevent this. I have a onPause method in MainActivity, but I don't have a reference of GetVideoAsyncTask launched from adapter. So I cannot call method AsyncTask.cancel(true) in order to deny intent launch.
Any suggestion?
Create an object of your async task class;
TvAsyncTask tvTask = new TvAsyncTask(getActivity(), gridView, progressBar);
tvTask.execute();
Then in the TvAsyncTask class override the onCanceled function
#Override
protected void onCancelled()
{
super.onCancelled();
}
In your back button code check:
if(tvTask != null)
tvTask.cancel(true);
in main activity you can keep a reference to GetVideoAsyncTask and TvAsyncTask and in onPause cancel both of them.
inActivity:
GetVideoAsyncTask getVideoAsyncTask;
TvAsyncTask tvAsyncTask;
in onCreate:
tvAsyncTask=new TvAsyncTask(getActivity(), gridView, progressBar);
tvAsyncTask.execute();
and in onItemClick
getVideoAsyncTask=new GetVideoAsyncTask(activity);
getVideoAsyncTask.execute(videoUrl);
in onPause:
if(tvAsyncTask!=null&&!tvAsyncTask.isCancelled())
tvAsyncTask.cancel(true);
if(getVideoAsyncTask!=null&&!getVideoAsyncTask.isCancelled())
getVideoAsyncTask.cancel(true);

Categories