Как сделать аудиоплеер с кнопкой воспроизведения/паузы и панелью поиска в recycleview

Мне нужна помощь, я хочу сделать вид повторного использования, содержащий звук в каждом элементе, как воспроизводить звук при нажатии кнопки воспроизведения и установить прогресс на панель поиска и в то же время приостановить другой звук и преобразовать кнопку воспроизведения в режим воспроизведения во всех строка, кроме воспроизводимой, находится в режиме паузы, например whatsapp или чаты в мессенджере facebook

Это мой код: MyAdapter.class

    private List<String> positions = new ArrayList<>();

  public myAdapter(Activity activity, ArrayList<Tweet> list) {
    this.activity = activity;
    this.list = list;
    mPlayer = new MediaPlayer();
    }
    public void onBindViewHolder(final viewHolder holder, final int position) {
        if (!positions.contains(String.valueOf(position)))
            positions.add(String.valueOf(position));
        }
        }

viewHolder.класс

  public class viewHolder extends RecyclerView.ViewHolder implements
        SeekBar.OnSeekBarChangeListener, View.OnClickListener {
    LinearLayout parentPanel;
    int viewType;
    private RelativeLayout pauseLayout, playLayout;
    private ImageView pauseIcon, playIcon;
    private SeekBar seekBar;
    private TextView periodTime;
    AudioCallbacks mAudioCallbacks;
    private int last_position;

    viewHolder(final View itemView, int viewType) {
        super(itemView);
        this.viewType = viewType;

            playLayout = (RelativeLayout) itemView.findViewById(R.id.play_layout);
            pauseLayout = (RelativeLayout) itemView.findViewById(R.id.pause_layout);
            playIcon = (ImageView) itemView.findViewById(R.id.play_icon);
            pauseIcon = (ImageView) itemView.findViewById(R.id.pause_icon);
            seekBar = (SeekBar) itemView.findViewById(R.id.seekBar);
            periodTime = (TextView) itemView.findViewById(R.id.period_time);


            seekBar.setOnSeekBarChangeListener(this);
            playLayout.setOnClickListener(this);
            pauseLayout.setOnClickListener(this);
            mAudioCallbacks = new AudioCallbacks() {
                @Override
                public void onUpdate(int percentage) {
                    seekBar.setProgress(percentage);
                    if (percentage == 100)
                        mAudioCallbacks.onStop();
                }
                @Override
                public void onPause() {
                    Log.i("on pause audio", " pause");
                }
                @Override
                public void onStop() {
                    Log.i("on stop audio", " stop");
                    stopPlayingAudio();
                }
            };
    }

    void stopPlayingAudio() {
        if (mPlayer != null) {
            if (mPlayer.isPlaying()) {
                updateAudioProgressBar();
                mPlayer.stop();
                mPlayer.reset();
                seekBar.setProgress(0);
                playLayout.setVisibility(View.VISIBLE);
                pauseLayout.setVisibility(View.GONE);
            }
        }
    }

    void pausePlayingAudio() {
        if (mPlayer != null) {
            if (mPlayer.isPlaying()) {
                mPlayer.pause();
                updateAudioProgressBar();
                mAudioCallbacks.onPause();
            }
        }
    }
    void playingAudio(Tweet message) {
        updateAudioProgressBar();
        if (mPlayer != null) {
            try {
                mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mPlayer.setDataSource(message.getAudioUrl());
                mPlayer.prepare();
                mPlayer.start();
                periodTime.setVisibility(View.VISIBLE);
                periodTime.setText(String.valueOf(message.getAudioDuration()));
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    void updateAudioProgressBar() {
        durationHandler.postDelayed(mUpdateTimeTask, 100);
    }
    private Runnable mUpdateTimeTask = new Runnable() {
        public void run() {
            try {
                if (mPlayer.isPlaying()) {
                    long totalDuration = mPlayer.getDuration();
                    long currentDuration = mPlayer.getCurrentPosition();
                    int progress = Utils.getProgressPercentage(currentDuration, totalDuration);
                    mAudioCallbacks.onUpdate(progress);
                    periodTime.setText(Utils.getFileTime(currentDuration));
                    durationHandler.postDelayed(this, 100);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    @Override
    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        durationHandler.removeCallbacks(mUpdateTimeTask);
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        int totalDuration = mPlayer.getDuration();
        int currentPosition = Utils.progressToTimer(seekBar.getProgress(), totalDuration);
        mPlayer.seekTo(currentPosition);
        updateAudioProgressBar();
    }

    @Override
    public void onClick(View view) {
        Log.e("getAdapterPosition()L", last_position + " /");
        for (String pos : positions) {
            if (!pos.equals(String.valueOf(getAdapterPosition())))
                notifyItemChanged(Integer.parseInt(pos));
        }
        last_position = getAdapterPosition();
        Log.e("getAdapterPosition()F", last_position + " /");
        Tweet message = list.get(getAdapterPosition());
        switch (view.getId()) {
            case R.id.pause_layout:
                playLayout.setVisibility(View.VISIBLE);
                pauseLayout.setVisibility(View.GONE);
                pausePlayingAudio();
                break;
            case R.id.play_layout:
                playLayout.setVisibility(View.GONE);
                pauseLayout.setVisibility(View.VISIBLE);
                mAudioCallbacks.onStop();
                playingAudio(message);
                break;
        }
    }
    }
    public interface AudioCallbacks {
    void onUpdate(int percentage);
    void onPause();
    void onStop();
    }

проблема этого кода:

  1. некоторое время изображение не перевернуто другого объекта при воспроизведении определенного элемента.
  2. при прокрутке кнопка паузы появляется в нескольких рядах.
  3. когда играешь в одну, затем играешь в другую, останавливаешь первую и запускаешь новую, но когда возвращаешься к предыдущей, не играешь.
  4. когда вы выходите из активности или нажимаете кнопку «Назад», звук не останавливается.

Может кто-нибудь помочь мне, пожалуйста?


person Amal Kronz    schedule 11.09.2017    source источник


Ответы (1)


Контролировать и обновлять прогресс MediaPlayer из RecyclerView ячеек сложно. Ваше решение неправильно обновляет состояния просмотра в вызове onBindViewHolder, что является основной причиной всех проблем, с которыми вы сталкиваетесь. Несколько других замечаний, которые следует иметь в виду, заключаются в следующем:

  • правильно обновлять состояние представления ячейки, что также включает добавление/удаление средства обновления прогресса
  • старайтесь избегать анонимного выделения xxxListeners, Runnables в onBindViewHolder, т.е. ViewHolder можно использовать для реализации xxxListener интерфейсов и т.д.
  • удалить средство обновления панели поиска, когда медиаплеер завершает воспроизведение аудио
  • уважайте жизненный цикл активности и отключайте/останавливайте медиаплеер, если он не требуется для воспроизведения аудио

Ниже источник показывает возможную реализацию Adapter

private class AudioItemAdapter extends RecyclerView.Adapter<AudioItemAdapter.AudioItemsViewHolder> {

    private MediaPlayer mediaPlayer;

    private List<AudioItem> audioItems;
    private int currentPlayingPosition;
    private SeekBarUpdater seekBarUpdater;
    private AudioItemsViewHolder playingHolder;

    AudioItemAdapter(List<AudioItem> audioItems) {
        this.audioItems = audioItems;
        this.currentPlayingPosition = -1;
        seekBarUpdater = new SeekBarUpdater();
    }

    @Override
    public AudioItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new AudioItemsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
    }

    @Override
    public void onBindViewHolder(AudioItemsViewHolder holder, int position) {
        if (position == currentPlayingPosition) {
            playingHolder = holder;
            updatePlayingView();
        } else {
            updateNonPlayingView(holder);
        }
    }

    @Override
    public void onViewRecycled(AudioItemsViewHolder holder) {
        super.onViewRecycled(holder);
        if (currentPlayingPosition == holder.getAdapterPosition()) {
            updateNonPlayingView(playingHolder);
            playingHolder = null;
        }
    }

    private void updateNonPlayingView(AudioItemsViewHolder holder) {
        holder.sbProgress.removeCallbacks(seekBarUpdater);
        holder.sbProgress.setEnabled(false);
        holder.sbProgress.setProgress(0);
        holder.ivPlayPause.setImageResource(R.drawable.ic_play_arrow);
    }

    private void updatePlayingView() {
        playingHolder.sbProgress.setMax(mediaPlayer.getDuration());
        playingHolder.sbProgress.setProgress(mediaPlayer.getCurrentPosition());
        playingHolder.sbProgress.setEnabled(true);
        if (mediaPlayer.isPlaying()) {
            playingHolder.sbProgress.postDelayed(seekBarUpdater, 100);
            playingHolder.ivPlayPause.setImageResource(R.drawable.ic_pause);
        } else {
            playingHolder.sbProgress.removeCallbacks(seekBarUpdater);
            playingHolder.ivPlayPause.setImageResource(R.drawable.ic_play_arrow);
        }
    }

    void stopPlayer() {
        if (null != mediaPlayer) {
            releaseMediaPlayer();
        }
    }

    private class SeekBarUpdater implements Runnable {
        @Override
        public void run() {
            if (null != playingHolder) {
                playingHolder.sbProgress.setProgress(mediaPlayer.getCurrentPosition());
                playingHolder.sbProgress.postDelayed(this, 100);
            }
        }
    }

    @Override
    public int getItemCount() {
        return audioItems.size();
    }

    class AudioItemsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, SeekBar.OnSeekBarChangeListener {
        SeekBar sbProgress;
        ImageView ivPlayPause;

        AudioItemsViewHolder(View itemView) {
            super(itemView);
            ivPlayPause = (ImageView) itemView.findViewById(R.id.ivPlayPause);
            ivPlayPause.setOnClickListener(this);
            sbProgress = (SeekBar) itemView.findViewById(R.id.sbProgress);
            sbProgress.setOnSeekBarChangeListener(this);
        }

        @Override
        public void onClick(View v) {
            if (getAdapterPosition() == currentPlayingPosition) {
                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                } else {
                    mediaPlayer.start();
                }
            } else {
                currentPlayingPosition = getAdapterPosition();
                if (mediaPlayer != null) {
                    if (null != playingHolder) {
                        updateNonPlayingView(playingHolder);
                    }
                    mediaPlayer.release();
                }
                playingHolder = this;
                startMediaPlayer(audioItems.get(currentPlayingPosition).audioResId);
            }
            updatePlayingView();
        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (fromUser) {
                mediaPlayer.seekTo(progress);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    }

    private void startMediaPlayer(int audioResId) {
        mediaPlayer = MediaPlayer.create(getApplicationContext(), audioResId);
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                releaseMediaPlayer();
            }
        });
        mediaPlayer.start();
    }

    private void releaseMediaPlayer() {
        if (null != playingHolder) {
            updateNonPlayingView(playingHolder);
        }
        mediaPlayer.release();
        mediaPlayer = null;
        currentPlayingPosition = -1;
    }
}

Вы можете найти полное рабочее решение здесь - GitHub

person user3161880    schedule 13.09.2017
comment
это действительно полезно - person Praveen; 29.09.2018
comment
Следил за демонстрацией GitHub, действительно здорово и полезно, спасибо. - person Mostafa Arian Nejad; 06.06.2019
comment
Единственная проблема, которую я обнаружил, заключается в том, что панель поиска не обновляется. А в github панель поиска не запускается с первого раза. Какие-либо предложения? - person Ashutosh Sagar; 08.05.2021