如何在循环视图中使用播放/暂停按钮和搜索栏制作音频播放器

时间:2017-09-11 12:42:51

标签: android android-mediaplayer audio-streaming playback android-seekbar

我需要一些帮助,我想制作一个包含每个项目音频的循环视图,如何在按下播放按钮时播放音频并将进度设置为搜索条,同时暂停其他声音并转换播放按钮进行播放所有行中的模式除了播放一个处于暂停模式 例如whatsapp或facebook messenger中的聊天

这是我的代码: 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.class

  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. 离开活动或按回按钮时声音没有停止。
  5. 有人可以帮助我吗?

1 个答案:

答案 0 :(得分:10)

MediaPlayer单元格控制和更新RecyclerView的进度非常棘手。您的解决方案未正确更新onBindViewHolder调用中的视图状态,这是您遇到的所有问题的根本原因。人们应该记住的其他几点注意事项如下:

  • 正确更新单元格视图状态,其中还包括添加/删除进度更新程序
  • 尽量避免在xxxListener中对RunnableonBindViewHolder进行匿名分配,即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