#java #android #android-mediaplayer
Вопрос:
Я создаю приложение для чата и реализовал функцию отправки аудиосообщений.Но здесь я нахожу одну вещь, которой я не хочу, чтобы это произошло.Дело в том,что всякий раз, когда мой адаптер обновляется, медиаплеер снова начинает загружаться. Таким образом ,возникнет проблема, поскольку, если кто-то слушает аудио, а пользователь на другом конце отправляет сообщение, медиаплеер останавливается и загружается снова.Вот код моего адаптера.
final MediaPlayer mediaPlayer;
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
handler = new Handler();
try {
mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
mediaPlayer1.stop();
binding.audioSeekbar.setProgress(0);
});
if (mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer.setDataSource(finalUrlToLoad[1]);
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
int totalDuration = mediaPlayer1.getDuration();
binding.totalDurationAudio.setText(createTimeLabel(totalDuration));
binding.loadingAudio.setVisibility(GONE);
binding.playPauseAudio.setVisibility(VISIBLE);
});
} catch (IOException e) {e.printStackTrace();}
binding.playPauseAudio.setOnClickListener(view -> {
if (mediaPlayer.isPlaying()){
handler.removeCallbacks(runnable);
mediaPlayer.pause();
binding.playPauseAudio.setImageResource(R.drawable.pause_to_play);
Drawable drawable = binding.playPauseAudio.getDrawable();
if( drawable instanceof AnimatedVectorDrawable) {
AnimatedVectorDrawable animation = (AnimatedVectorDrawable) drawable;
animation.start();
}
}else {
mediaPlayer.seekTo(binding.audioSeekbar.getProgress());
mediaPlayer.start();
handler.post(runnable);
binding.playPauseAudio.setImageResource(R.drawable.play_to_pause);
Drawable drawable = binding.playPauseAudio.getDrawable();
if( drawable instanceof AnimatedVectorDrawable) {
AnimatedVectorDrawable animation = (AnimatedVectorDrawable) drawable;
animation.start();
}
}
});
runnable = () -> {
int totalTime = mediaPlayer.getDuration();
binding.audioSeekbar.setMax(totalTime);
int currentPosition = mediaPlayer.getCurrentPosition();
binding.audioSeekbar.setProgress(currentPosition);
binding.totalDurationAudio.setText(createTimeLabel(totalTime));
Log.d("time", String.valueOf(currentPosition));
handler.postDelayed(runnable,1000);
};
binding.audioSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if (b){
mediaPlayer.seekTo(i);
seekBar.setProgress(i);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
mediaPlayer.setOnBufferingUpdateListener((mediaPlayer1, i) -> binding.audioSeekbar.setSecondaryProgress(i));
Здесь finalurltoload[1] — это URL-адрес для аудио.
Теперь, что мне нужно сделать, чтобы предотвратить загрузку его снова и снова.
Я буду очень благодарен тем, кто ответит на этот вопрос.
Спасибо😊.
Ответ №1:
Трудно сказать по этому коду, но я предполагаю, что все это задано в вашем событии onBind? Если это так, то это означает, что каждый раз, когда RecyclerView создает новый держатель и привязывает его, связанный носитель будет подготовлен и загружен, и в зависимости от того, какой последний держатель был вызван с помощью onBind, «выигрывает» (и это то, с чем будет загружен MediaPlayer). Поскольку по умолчанию RecyclerView обычно создает несколько держателей заранее, вы видите, что ваш медиаплеер «загружается» несколько раз.
Вероятно, вы просто не хотите выполнять инициализацию каждого аудиосообщения в привязке. Вместо этого просто используйте событие onBind для инициализации переменных состояния (длительность, прогресс и т.д.) До некоторого значения по умолчанию, скройте их и свяжите конкретный Uri аудио. Затем, когда пользователь выполняет какое-либо действие, например, нажимает на держатель, вы показываете неопределенный индикатор выполнения во время инициализации, а в событии onPrepared() показываете информацию о состоянии (продолжительность, прогресс, панель поиска и т. Д.) И, Наконец, скрываете неопределенный индикатор выполнения и запускаете звук.
Я предполагаю, что вы также отправляете звуковой файл как часть своего приложения для обмена сообщениями (т. Е. Не храните его в Интернете где-то в центральном месте?), и этот файл хранится в хранилище для конкретного приложения? Если это так, вам не нужно беспокоиться о сохранении разрешения на этот URI, но если это не так, вы это сделаете.
Комментарии:
1. сообщения сохраняются в firebase Firestore, а аудио-в хранилище firebase.
2. Тогда сохраняемый вами Uri, указывающий на них, не выдержит перезагрузки устройства, если ваше приложение не сохранит разрешения, связанные с открытием Uri, чтобы иметь возможность получить к ним доступ в будущем. И вы получаете только определенное количество из них в зависимости от версии вашего API (128 до API 9, я полагаю, 512 после). Вот хорошая статья об этом, особенно об воспроизведении звуков: wochstudios.com/persistent-uri-permissions-in-android
Ответ №2:
- Сначала извлеките код медиаплеера в одноэлементный класс, например AudioManager.
- Добавьте несколько методов, таких как setMediaUpdateListener, которые устанавливают обратный вызов на время поиска. и включите воспроизведение, чтобы воспроизвести или приостановить звук.
- Передал идентификатор сообщения или любой другой уникальный идентификатор аудиоменеджеру во время воспроизведения видео.
В классе адаптера Метод onBind.
- Сначала сравните идентификатор и идентификатор воспроизведения, такой же, как AudioManager.getInstance().isPlaying(MessageId);
- Если да, то установите класс seekUpdatelistner в класс audio manager. также обновите значок воспроизведения/паузы на основе метода AudioManager.isPlaying ().
3.если пользователь воспроизводит другое сообщение, нажав кнопку воспроизведения. вызовите метод AudioManager.play(сообщение).В которой мы выпускаем предыдущее сообщение и воспроизводим новое.
- Если текущее сообщение не воспроизводится, сбросьте представление в состояние «Не воспроизводится».
- Если автоматическое воспроизведение включено, вам необходимо проверить, свободен ли AudioManager, тогда только вы можете воспроизвести последнее сообщение, в противном случае проигнорированное.
Как класс, который управляет звуком для вас и хранит все состояние.
class AudioManager {
public static AudioManager instance;
final MediaPlayer mediaPlayer;
private AudioListener audioListener;
private Uri currentPlaying;
public AudioManager getInstance() {
if (instance == null) {
instance = new AudioManager();
}
}
public void play(Uri dataUri) {
if (mediaPlayer != null amp;amp; currentPlaying == null || currentPlaying.equals(dataUri)) {
if (!mediaPlayer.isPlaying) {
mediaPlayer.play();
}
return;
} else if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
handler = new Handler();
try {
mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
mediaPlayer1.stop();
sendProgress(0);
});
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
}
mediaPlayer.setDataSource(dataUri;
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
int totalDuration = mediaPlayer1.getDuration();
sendTotalDuration(totalDuration);
});
} catch (IOException e) {
e.printStackTrace();
}
}
public void pause() {
// update the pause code.
}
public void sendProgress(int progress) {
if (audioListener != null) {
audioListener.onProgress(progress);
}
}
public void sendTotalDuration(int duration) {
if (audioListener != null) {
audioListener.onTotalDuraration(duration);
}
}
public void AudioListener(AudioListener audioListener) {
this.audioListener = audioListener;
}
public interface AudioListener {
void onProgress(int progress);
void onTotalDuraration(int duration);
void onAudioPlayed();
void onAudioPaused():
}
}
Комментарии:
1.
First extract the media player code into singleton class like AudioManager
.Я не понял, что вы подразумеваете под извлечением кода медиаплеера2. И как мне добавить одноэлементный класс.
3. Я добавил код, чтобы продемонстрировать, как вы можете двигаться дальше
4. это` медиаплеер.воспроизведение` медиаплеер.запуск
5.
https://i.stack.imgur.com/FmxDM.png
это дает ошибку. Проверьте изображение.