Медиаплеер снова и снова загружает носители

#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:

  1. Сначала извлеките код медиаплеера в одноэлементный класс, например AudioManager.
  2. Добавьте несколько методов, таких как setMediaUpdateListener, которые устанавливают обратный вызов на время поиска. и включите воспроизведение, чтобы воспроизвести или приостановить звук.
  3. Передал идентификатор сообщения или любой другой уникальный идентификатор аудиоменеджеру во время воспроизведения видео.

В классе адаптера Метод onBind.

  1. Сначала сравните идентификатор и идентификатор воспроизведения, такой же, как AudioManager.getInstance().isPlaying(MessageId);
  2. Если да, то установите класс seekUpdatelistner в класс audio manager. также обновите значок воспроизведения/паузы на основе метода AudioManager.isPlaying ().

3.если пользователь воспроизводит другое сообщение, нажав кнопку воспроизведения. вызовите метод AudioManager.play(сообщение).В которой мы выпускаем предыдущее сообщение и воспроизводим новое.

  1. Если текущее сообщение не воспроизводится, сбросьте представление в состояние «Не воспроизводится».
  2. Если автоматическое воспроизведение включено, вам необходимо проверить, свободен ли 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 это дает ошибку. Проверьте изображение.