SeekBar и медиаплеер в android
У меня есть простой плеер и рекордер. Все работает отлично, но есть одна проблема. Я хочу добавить панель поиска, чтобы увидеть прогресс в воспроизведении записи и использовать эту панель поиска, чтобы установить место от игрока. У меня есть 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
    }
}
любые идеи, как использовать панель поиска, чтобы увидеть прогресс и установить место из записи, должны играть?
11 ответов
создать связь между SeekBar и MediaPlayer сначала вам нужно получить текущую максимальную продолжительность записи и установить ее на панель поиска.
mSeekBar.setMax(mFileDuration); // where mFileDuration is mMediaPlayer.getDuration();
после инициализации вашего MediaPlayer и, например, нажмите кнопку воспроизведения, вы должны создать обработчик и опубликовать runnable, чтобы вы могли обновить свой SeekBar (в UI thread сам) с текущей позицией вашего MediaPlayer такой :
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);
    }
});
и обновляйте это значение каждую секунду.
если вам необходимо обновить MediaPlayer's позиция в то время как пользователь перетащить SeekBar вы должны добавить 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);
                }
            }
    });
и это должно сделать трюк! : )
EDIT: Одна вещь, которую я заметил в вашем коде, не надо :
public MainActivity() {
    mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
    mFileName += "/audiorecordtest.3gp";
}
сделать все initialisations в onCreate();, не создавайте конструкторы вашего Activity.
я использовал этот учебник с успехом, это очень просто понять: 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();
}
после инициализации MediaPlayer и SeekBar, вы можете сделать это :
 Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
        }
    },0,1000);
обновления SeekBar каждую секунду (1000ms)
и для обновления 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) {
        }
    });
СЧАСТЛИВОЕ КОДИРОВАНИЕ!!!
проверьте это, вы должны дать аргументы в msecs, не просто отправить progress до seekTo (int)
а также проверьте это getCurrentPostion() и getDuration().
вы можете сделать некоторые вычисления, т. е. преобразуйте progress в msec как msce = (progress/100)*getDuration() затем сделать seekTo(msec)
или еще у меня есть простая идея, вам не нужно менять какой-либо код anywer, просто добавьте seekBar.setMax(mPlayer.getDuration()) как только ваш медиаплеер будет готов.
и вот ссылка именно то, что вы хотите обновление панели поиска
    int  pos  = 0;
    yourSeekBar.setMax(mPlayer.getDuration());
после MediaPlayer Я.е mplayer.start()
попробуйте этот код
while(mPlayer!=null){
         try {
                Thread.sleep(1000);
                pos  = mPlayer.getCurrentPosition();
            }  catch (Exception e) {
                //show exception in LogCat
            }
            yourSeekBar.setProgress(pos);
   }
прежде чем добавить этот код, вы должны создать xml ресурс SeekBar и используйте его в своем Activity класс ur onCreate() метод.
чтобы добавить к ответу @hardartcore.
- вместо вызова postDelayed на обработчике, лучшим подходом было бы получить обратные вызовы от - MediaPlayerво время воспроизведения, а затем соответственно обновите панель поиска с прогрессом.
- кроме того, приостановите - MediaPlayerat- onStartTrackingTouch(SeekBar seekBar)на- OnSeekBarChangeListenerа затем снова запустите его на- onStopTrackingTouch(SeekBar seekBar).
на основе предыдущих операторов для повышения производительности вы также можете добавить условие if
if (player.isPlaying() {
    handler.postDelayed(..., 1000);
}
ниже код работал для меня.
Я создал метод для 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, чтобы показать продолжительность песни и длину песни.
это работает для меня:
seekbarPlayer.setMax(mp.getDuration());
getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        if(mp != null){
            seekbarPlayer.setProgress(mp.getCurrentPosition());
        }
        mHandler.postDelayed(this, 1000);
    }
});
попробуйте этот код:
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) {
                }
            });
        }
код в Котлин:
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)
            }
        }
для изменения аудиофайла медиаплеера каждую секунду
если пользователь перетаскивает строку поиска, то следующий фрагмент кода можно использовать
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) {}
        })
