【问题标题】:SeekBar and media player in android安卓中的 SeekBar 和媒体播放器
【发布时间】:2013-06-14 15:05:04
【问题描述】:

我有一个简单的播放器和录音机。一切都很好,但有一个问题。我想添加搜索栏以查看播放记录的进度,并使用此搜索栏设置播放器应该播放的位置。我有 onProgress 但没有效果。这是代码:

package com.example.recorder;

import java.io.IOException;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity implements OnSeekBarChangeListener
{
    private static final String LOG_TAG = "AudioRecordTest";
    private static String mFileName = null;
    private SeekBar seekBar;
    private MediaRecorder mRecorder = null;
    private Button startRecord, startPlaying, stopPlaying;
    private MediaPlayer   mPlayer = null;

    private void onRecord(boolean start) {
        if (start) {
            startRecording();
        } else {
            stopRecording();
        }
    }



    private void startPlaying() {
        if(mPlayer != null && mPlayer.isPlaying()){
            mPlayer.pause();
        } else if(mPlayer != null){
            mPlayer.start();
        }else{
        mPlayer = new MediaPlayer();
        try {

            mPlayer.setDataSource(mFileName);
            mPlayer.prepare();
            mPlayer.start();

        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
        }
        }

    }

    private void stopPlaying() {
        mPlayer.release();
        mPlayer = null;
        startPlaying.setText("Start playing");
    }

    private void pausePlaying(){
        if(mPlayer.isPlaying()){
            mPlayer.pause();
        } else {
          mPlayer.start();
        }
    }

    private void startRecording() {
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mRecorder.setOutputFile(mFileName);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            mRecorder.prepare();
        } catch (IOException e) {
            Log.e(LOG_TAG, "prepare() failed");
        }

        mRecorder.start();
    }

    private void stopRecording() {
        mRecorder.stop();
        mRecorder.release();
        mRecorder = null;
    }



    public MainActivity() {
        mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
        mFileName += "/audiorecordtest.3gp";
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        setContentView(R.layout.activity_main);

        startPlaying = (Button) findViewById(R.id.buttonStartPlay);
        stopPlaying = (Button) findViewById(R.id.buttonStopPlaying);
        startRecord = (Button) findViewById(R.id.buttonStartRecord);
        seekBar = (SeekBar) findViewById(R.id.seekBar);

        startRecord.setOnClickListener(new OnClickListener() {
            boolean mStartRecording = true;
            @Override
            public void onClick(View v) {
                onRecord(mStartRecording);
                if (mStartRecording) {
                    startRecord.setText("Stop recording");
                } else {
                    startRecord.setText("Start recording");
                }
                mStartRecording = !mStartRecording;

            }
        });  


        startPlaying.setOnClickListener(new OnClickListener() {
            boolean mStartPlaying = true;
            @Override
            public void onClick(View v) {
                //onPlay(mStartPlaying);
                startPlaying();
                if (mStartPlaying) {
                    startPlaying.setText("Stop playing");
                } else {
                    startPlaying.setText("Start playing");
                }
                mStartPlaying = !mStartPlaying;
            }
        });

        stopPlaying.setOnClickListener(new OnClickListener() {
            boolean mStartPlaying = true;
            @Override
            public void onClick(View v) {
                 stopPlaying();

            }
        });


    }

    @Override
    public void onPause() {
        super.onPause();
        if (mRecorder != null) {
            mRecorder.release();
            mRecorder = null;
        }

        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }



    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
        if(fromUser){
            mPlayer.seekTo(progress); 
            seekBar.setProgress(progress);
            }
            else{
             // the event was fired from code and you shouldn't call player.seekTo()
            }

    }



    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

    }



    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

    }
}

任何想法应该如何使用搜索栏查看进度并设置记录位置?

【问题讨论】:

  • onProgressChanged()它的冗余中删除`seekBar.setProgress(progress);`。
  • 您的评论不会改变任何事情:)
  • 我刚刚发现,它没用。它只是建议没有回答:)

标签: android android-mediaplayer android-seekbar


【解决方案1】:

要在 SeekBarMediaPlayer 之间创建“连接”,您首先需要获取当前录制的最长持续时间并将其设置到搜索栏。

mSeekBar.setMax(mFileDuration/1000); // where mFileDuration is mMediaPlayer.getDuration();

在初始化 MediaPlayer 并例如按下播放按钮后,您应该创建处理程序并发布可运行文件,以便您可以使用 MediaPlayer 的当前位置更新您的 SeekBar(在 UI thread 本身中)这个:

private Handler mHandler = new Handler();
//Make sure you update Seekbar on UI thread
MainActivity.this.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        if(mMediaPlayer != null){
            int mCurrentPosition = mMediaPlayer.getCurrentPosition() / 1000;
            mSeekBar.setProgress(mCurrentPosition);
        }
        mHandler.postDelayed(this, 1000);
    }
});

并每秒更新该值。

如果您需要在用户拖动您的SeekBar 时更新MediaPlayer 的位置,您应该将OnSeekBarChangeListener 添加到您的SeekBar 并在那里执行:

        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {                
                if(mMediaPlayer != null && fromUser){
                    mMediaPlayer.seekTo(progress * 1000);
                }
            }
    });

这应该可以解决问题! :)

编辑: 我在您的代码中注意到的一件事,不要这样做:

public MainActivity() {
    mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
    mFileName += "/audiorecordtest.3gp";
}

在您的 onCreate(); 中进行所有初始化,不要创建您的 Activity 的构造函数。

【讨论】:

  • 只是为了概念上的理解,为什么不在onCreate中创建构造函数并进行初始化呢?你听起来构造函数会出故障吗?
  • 是的,最好的方法。请注意:如果您执行 int mCurrentPosition = mMediaPlayer.getCurrentPosition() / 1000;那么你可能也必须这样做:mSeekBar.setMax(mFileDuration / 1000);
  • 这条线真的让我从if(mMediaPlayer != null && fromUser)之前的滞后问题中解脱出来,非常感谢+1
  • 如何强调验证progressChange 是否由用户触发的重要性。否则,每次调用 setProgress 时,都会每秒调用一次 onProgressChanged 回调,重置搜索位置。谢谢!
  • 还记得在媒体播放器暂停或到达音频文件结尾时删除 runnable,否则 runnable 将继续运行,意识到这一点是因为我每次运行 runnable 时都会记录,并获得大量日志。不过感谢您的解决方案,除此之外它工作得很好
【解决方案2】:

我已经成功地使用了这个教程,它真的很容易理解: www.androidhive.info/2012/03/android-building-audio-player-tutorial/

这是有趣的部分:

/**
 * Update timer on seekbar
 * */
public void updateProgressBar() {
    mHandler.postDelayed(mUpdateTimeTask, 100);
}  

/**
 * Background Runnable thread
 * */
private Runnable mUpdateTimeTask = new Runnable() {
       public void run() {
           long totalDuration = mp.getDuration();
           long currentDuration = mp.getCurrentPosition();

           // Displaying Total Duration time
           songTotalDurationLabel.setText(""+utils.milliSecondsToTimer(totalDuration));
           // Displaying time completed playing
           songCurrentDurationLabel.setText(""+utils.milliSecondsToTimer(currentDuration));

           // Updating progress bar
           int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration));
           //Log.d("Progress", ""+progress);
           songProgressBar.setProgress(progress);

           // Running this thread after 100 milliseconds
           mHandler.postDelayed(this, 100);
       }
    };

/**
 *
 * */
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {

}

/**
 * When user starts moving the progress handler
 * */
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
    // remove message Handler from updating progress bar
    mHandler.removeCallbacks(mUpdateTimeTask);
}

/**
 * When user stops moving the progress hanlder
 * */
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
    mHandler.removeCallbacks(mUpdateTimeTask);
    int totalDuration = mp.getDuration();
    int currentPosition = utils.progressToTimer(seekBar.getProgress(), totalDuration);

    // forward or backward to certain seconds
    mp.seekTo(currentPosition);

    // update timer progress again
    updateProgressBar();
}

【讨论】:

    【解决方案3】:

    初始化MediaPlayerSeekBar 后,您可以这样做:

     Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
            }
        },0,1000);
    

    这会更新 SeekBar 每秒(1000 毫秒)

    对于更新MediaPlayer,如果用户拖动SeekBar,您必须将OnSeekBarChangeListener添加到您的SeekBar

    mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                mMediaPlayer.seekTo(i);
            }
    
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
    
            }
    
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
    
            }
        });
    

    编码愉快!!!

    【讨论】:

      【解决方案4】:

      Kotlin 中的代码:

      var updateSongTime = object : Runnable {
                  override fun run() {
                      val getCurrent = mediaPlayer?.currentPosition
                      startTimeText?.setText(String.format("%d:%d",
                              TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong() as Long),
                              TimeUnit.MILLISECONDS.toSeconds(getCurrent?.toLong()) -
                                      TimeUnit.MINUTES.toSeconds(
                                              TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong()))))
                      seekBar?.setProgress(getCurrent?.toInt() as Int)
                      Handler().postDelayed(this, 1000)
                  }
              }
      

      用于每秒更改媒体播放器音频文件

      如果用户拖动搜索栏,则可以使用以下代码 sn-p

      Statified.seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                  override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
                      if(b && Statified.mediaPlayer != null){
                          Statified.mediaPlayer?.seekTo(i)
                      }
      
                  }
                  override fun onStartTrackingTouch(seekBar: SeekBar) {}
                  override fun onStopTrackingTouch(seekBar: SeekBar) {}
              })
      

      【讨论】:

        【解决方案5】:

        检查这个,你应该以毫秒为单位给出参数,不要只发送progressseekTo(int)

        还要检查getCurrentPostion()getDuration()

        您可以进行一些计算,即,以毫秒为单位转换 progress,如 msce = (progress/100)*getDuration(),然后执行 seekTo(msec)

        否则我有一个简单的想法,您无需更改任何代码,否则只需在准备好媒体播放器后添加seekBar.setMax(mPlayer.getDuration())

        这里是你想要的链接seek bar update

        【讨论】:

          【解决方案6】:

          下面的代码对我有用。

          我已经为 seekbar 创建了一个方法

          @Override
          public void onPrepared(MediaPlayer mediaPlayer) {
              mp.start();
               getDurationTimer();
              getSeekBarStatus();
          
          
          }
          //Creating duration time method
          public void getDurationTimer(){
              final long minutes=(mSongDuration/1000)/60;
              final int seconds= (int) ((mSongDuration/1000)%60);
              SongMaxLength.setText(minutes+ ":"+seconds);
          
          
          }
          
          
          
           //creating a method for seekBar progress
          public void getSeekBarStatus(){
          
              new Thread(new Runnable() {
          
                  @Override
                  public void run() {
                      // mp is your MediaPlayer
                      // progress is your ProgressBar
          
                      int currentPosition = 0;
                      int total = mp.getDuration();
                      seekBar.setMax(total);
                      while (mp != null && currentPosition < total) {
                          try {
                              Thread.sleep(1000);
                              currentPosition = mp.getCurrentPosition();
                          } catch (InterruptedException e) {
                              return;
                          }
                          seekBar.setProgress(currentPosition);
          
                      }
                  }
              }).start();
          
          
          
          
          
              seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                  int progress=0;
          
                  @Override
                  public void onProgressChanged(final SeekBar seekBar, int ProgressValue, boolean fromUser) {
                      if (fromUser) {
                          mp.seekTo(ProgressValue);//if user drags the seekbar, it gets the position and updates in textView.
                      }
                      final long mMinutes=(ProgressValue/1000)/60;//converting into minutes
                      final int mSeconds=((ProgressValue/1000)%60);//converting into seconds
                      SongProgress.setText(mMinutes+":"+mSeconds);
                  }
          
                  @Override
                  public void onStartTrackingTouch(SeekBar seekBar) {
          
                  }
          
                  @Override
                  public void onStopTrackingTouch(SeekBar seekBar) {
          
                  }
              });
          }
          

          SongProgress 和 SongMaxLength 是显示歌曲时长和歌曲长度的 TextView。

          【讨论】:

            【解决方案7】:
                int  pos  = 0;
                yourSeekBar.setMax(mPlayer.getDuration());
            

            在你开始你的MediaPlayermplayer.start()之后

            试试这个代码

            while(mPlayer!=null){
                     try {
                            Thread.sleep(1000);
                            pos  = mPlayer.getCurrentPosition();
                        }  catch (Exception e) {
                            //show exception in LogCat
                        }
                        yourSeekBar.setProgress(pos);
            
               }
            

            在添加此代码之前,您必须为 SeekBar 创建 xml 资源,并在您的 Activity 类的 onCreate() 方法中使用它。

            【讨论】:

              【解决方案8】:

              这对我有用:

              seekbarPlayer.setMax(mp.getDuration());
              getActivity().runOnUiThread(new Runnable() {
              
                  @Override
                  public void run() {
                      if(mp != null){
                          seekbarPlayer.setProgress(mp.getCurrentPosition());
                      }
                      mHandler.postDelayed(this, 1000);
                  }
              });
              

              【讨论】:

                【解决方案9】:

                鉴于答案hardartcore 对我有用,但在更改之前没有用:

                private Handler mHandler = new Handler();
                MusicPlayer.this.runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
                          if(player != null){
                               int mCurrentPosition = player.getCurrentPosition();//clear ' /1000 '
                               seekBar.setProgress(mCurrentPosition);
                          }
                          mHandler.postDelayed(this, 1000);
                      }
                });
                
                
                
                seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                
                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {
                
                    }
                
                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {
                
                    }
                
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                          if(player != null && fromUser){
                              player.seekTo(progress); // clear ' * 1000  '
                          }
                     }
                });
                

                【讨论】:

                  【解决方案10】:

                  我的代码sn-p:

                  public class PlayerActivity extends AppCompatActivity {
                  
                  private static final String TAG = "PlayerActivity";
                  private ActivityPlayerBinding binding;
                  private MediaPlayer mediaPlayer;
                  private boolean playingAudio = false;
                  Runnable runnable;
                  Handler handler;
                  
                  
                   protected void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
                      binding = ActivityPlayerBinding.inflate(getLayoutInflater());
                      setContentView(binding.getRoot());
                  
                          mediaPlayer = new MediaPlayer();
                      mediaPlayer.setAudioAttributes(
                              new AudioAttributes.Builder()
                                      .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                                      .setUsage(AudioAttributes.USAGE_MEDIA)
                                      .build()
                      );
                  
                      try {
                          mediaPlayer.setDataSource(songUrl);
                          mediaPlayer.prepareAsync();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  
                      mediaPlayer.setOnPreparedListener(mp -> {
                          binding.playBtn.setBackground(getDrawable(R.drawable.ic_pause));
                          binding.seekbarPlayer.setMax(mp.getDuration());
                          mediaPlayer.start();
                          playingAudio = true;
                          updateSeekbar();
                      });
                  
                      mediaPlayer.setOnBufferingUpdateListener((mp, percent) -> {
                          double ratio = percent / 100.0;
                          int bufferingLevel = (int) (mp.getDuration() * ratio);
                          binding.seekbarPlayer.setSecondaryProgress(bufferingLevel);
                      });
                  
                      binding.seekbarPlayer.setOnSeekBarChangeListener(seekBarChangeListener);
                  
                  }
                  
                      private SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
                      @Override
                      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                          if (fromUser) {
                              mediaPlayer.seekTo(progress);
                              seekBar.setProgress(progress);
                          }
                      }
                  
                      @Override
                      public void onStartTrackingTouch(SeekBar seekBar) {
                  
                      }
                  
                      @Override
                      public void onStopTrackingTouch(SeekBar seekBar) {
                  
                      }
                  };
                      private void updateSeekbar() {
                      try {
                          if (mediaPlayer != null) {
                              int currentPos = mediaPlayer.getCurrentPosition();
                              binding.seekbarPlayer.setProgress(currentPos);
                              runnable = this::updateSeekbar;
                              handler.postDelayed(runnable, 1000);
                          }
                      } catch (Exception e) {
                          e.printStackTrace();
                          Log.d(TAG, "updateSeekbar: " + e.getMessage());
                      }  
                    }
                  }
                  

                  【讨论】:

                    【解决方案11】:

                    补充@hardartcore 的答案。

                    1. 最好的方法是在播放期间从 MediaPlayer 获取回调,然后根据进度相应地更新 seekBar,而不是在 Handler 上调用 postDelayed。

                    2. 另外,在OnSeekBarChangeListeneronStartTrackingTouch(SeekBar seekBar) 处暂停MediaPlayer,然后在onStopTrackingTouch(SeekBar seekBar) 上重新启动它。

                    【讨论】:

                      【解决方案12】:

                      在前面的语句的基础上,为了更好的性能,还可以加一个if条件

                      if (player.isPlaying() {
                          handler.postDelayed(..., 1000);
                      }
                      

                      【讨论】:

                        【解决方案13】:

                        试试这个代码:

                        public class MainActivity extends AppCompatActivity {
                        
                        MediaPlayer mplayer;
                        
                        @Override
                        protected void onCreate(Bundle savedInstanceState) {
                            super.onCreate(savedInstanceState);
                            setContentView(R.layout.activity_main);
                        
                                    //You create MediaPlayer variable ==> set the path and start the audio.
                        
                            mplayer = MediaPlayer.create(this, R.raw.example);
                            mplayer.start();
                        
                                    //Find the seek bar by Id (which you have to create in layout)
                                    // Set seekBar max with length of audio
                                   // You need a Timer variable to set progress with position of audio
                        
                            final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
                            seekBar.setMax(mplayer.getDuration());
                        
                            new Timer().scheduleAtFixedRate(new TimerTask() {
                                        @Override
                                        public void run() {
                                            seekBar.setProgress(mplayer.getCurrentPosition());
                                        }
                                    }, 0, 1000);
                        
                        
                                    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                                        @Override
                                        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                        
                                    // Update the progress depending on seek bar
                                            mplayer.seekTo(progress);
                        
                                        }
                        
                                        @Override
                                        public void onStartTrackingTouch(SeekBar seekBar) {
                        
                                        }
                        
                                        @Override
                                        public void onStopTrackingTouch(SeekBar seekBar) {
                        
                                        }
                                    });
                                }
                        

                        【讨论】:

                        • 您可能希望在解决方案中的代码中添加一些上下文,以帮助其他人更有效地理解解决方案。
                        猜你喜欢
                        • 1970-01-01
                        • 2013-02-03
                        • 2011-09-03
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-05-05
                        • 1970-01-01
                        相关资源
                        最近更新 更多