Mediaplayer progress update to seekbar not smooth?

前端 未结 6 2025
情话喂你
情话喂你 2021-02-01 07:00

I am working on an app with recorder and player. I am using mediaplayer to play the recorded .wav file and meantime I want to update to a seekbar. Everything is working fine But

相关标签:
6条回答
  • 2021-02-01 07:22

    seekbar.setProgress() only accepts int. Hence, most of us tend to pass the elapsed percentage to this method. However, if you need much smoother progression, then you can use the duration in milliseconds as the MAX. Then we get to update the progression of the seekbar every millisecond. Below is an example and I have updated it every 15th millisecond as almost every android phone comes with a refresh rate of 60 fps (frames per second).

        try{
            mediaPlayer.start();
            seekbar.setProgress(0);
            seekbar.setMax(mediaPlayer.getDuration());
    
            // Updating progress bar
            seekHandler.postDelayed(updateSeekBar, 15);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    
    /**
     * Background Runnable thread
     * */
    private Runnable updateSeekBar = new Runnable() {
        public void run() {
            long totalDuration = mediaPlayer.getDuration();
            long currentDuration = mediaPlayer.getCurrentPosition();
    
            // Displaying Total Duration time
            remaining.setText(""+ milliSecondsToTimer(totalDuration-currentDuration));
            // Displaying time completed playing
            elapsed.setText(""+ milliSecondsToTimer(currentDuration));
    
            // Updating progress bar
            seekbar.setProgress((int)currentDuration);
    
            // Call this thread again after 15 milliseconds => ~ 1000/60fps
            seekHandler.postDelayed(this, 15);
        }
    };
    
    /**
     * Function to convert milliseconds time to
     * Timer Format
     * Hours:Minutes:Seconds
     * */
    public String milliSecondsToTimer(long milliseconds){
        String finalTimerString = "";
        String secondsString = "";
    
        // Convert total duration into time
        int hours = (int)( milliseconds / (1000*60*60));
        int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60);
        int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) / 1000);
        // Add hours if there
        if(hours > 0){
            finalTimerString = hours + ":";
        }
    
        // Prepending 0 to seconds if it is one digit
        if(seconds < 10) {
            secondsString = "0" + seconds;
        }else {
            secondsString = "" + seconds;
        }
    
        finalTimerString = finalTimerString + minutes + ":" + secondsString;
    
        // return timer string
        return finalTimerString;
    }
    
    0 讨论(0)
  • 2021-02-01 07:28

    The problem you're experiencing has to do with the way Android's SeekBar is designed/implemented. While it functions very well, you're limited by a combination of segments used (i.e. seekbar.setMax(int)) and the delay time of your Handler.

    That being said, I subclassed SeekBar to make my own SmoothSeekBar that uses ViewPropertyAnimators instead of a Handler.

    Check it out here: https://github.com/Indatus/Android-SmoothSeekBar

    0 讨论(0)
  • 2021-02-01 07:32

    mMediaPlayer.getCurrentPosition() Return current Time in millisecond and you are updating this to Seekbar which maximum capacity is 100. Make one formula to with length of file and 100. try this function

        MediaPlayer mMediaPlayer = new MediaPlayer();
        final SeekBar mSeelBar = new SeekBar(this);
        final int duration = mMediaPlayer.getDuration();
        final int amoungToupdate = duration / 100;
        Timer mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
    
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
    
                    @Override
                    public void run() {
                        if (!(amoungToupdate * mSeelBar.getProgress() >= duration)) {
                            int p = mSeelBar.getProgress();
                            p += 1;
                            mSeelBar.setProgress(p);
                        }
                    }
                });
            };
        }, amoungToupdate);
    

    And this process should be called when Media player start playing. inside

        mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
    
            @Override
            public void onPrepared(MediaPlayer mp) {
            **// call here**
            }
        });
    

    Update

    Update 125 times in seconds is not something you should do. Please increase your interval for updating SeekBar. I adding this after reading comments of NullPointer

    0 讨论(0)
  • 2021-02-01 07:37

    Here is how i handle the seekbar;

            mediaPlayer.setOnPreparedListener(new OnPreparedListener(){
    
            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();
                new SeekBarHandler().execute();
        });
    

    Now i have an Async Task called SeekBarHandler that handles the seekbar like this:

        public class SeekBarHandler extends AsyncTask<Void, Void, Void> {
    
    @Override
    protected void onPostExecute(Void result) {
        Log.d("##########Seek Bar Handler ################","###################Destroyed##################");
        super.onPostExecute(result);
    }
    
    @Override
    protected void onProgressUpdate(Void... values) {
        seekBar.setProgress(mediaPlayer.getCurrentPosition());
        super.onProgressUpdate(values);
    }
    
    @Override
    protected Void doInBackground(Void... arg0) {
        while(mediaPlayer.isPlaying()&&isViewOn==true) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        onProgressUpdate();
        }
        return null;
    }
    
        }
    

    Now in my onPause, i terminate the AsyncTask as it doesnt make sense to keep the thread going when the user is not able to see the seekbar

        protected void onPause() {
        isViewOn=false;
        super.onPause();
        }
    

    And on onResume i start the AsyncTaskAgain like this

        protected void onResume() {
        isViewOn=true;
        new SeekBarHandler().execute();
        super.onResume();
        }
    

    As you can see i use a boolean flag isViewOn to check whether the view is on or not to handle the seekbar.

    0 讨论(0)
  • 2021-02-01 07:38
    player.prepare(); // or start()
    
    ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
    service.scheduleWithFixedDelay(new Runnable()
    {
      @Override
      public void run()
      {
        progressBar.setProgress(player.getCurrentPosition());
      }
    }, 1, 1, TimeUnit.MICROSECONDS);
    
    0 讨论(0)
  • 2021-02-01 07:41
    private void startPlaying() {
            mediaPlayer = new MediaPlayer();
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(audioPlayerName);
                mediaPlayer.prepare();
                mediaPlayer.start();
    
                setAudioProgress(); //call method
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
    public void setAudioProgress() {
        total_duration = mediaPlayer.getDuration();
    
        binding.total.setText(timeConversion((long) total_duration));
        binding.current.setText(timeConversion((long) current_pos));
        binding.seekbar.setMax((int) total_duration);
    
        runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    current_pos = mediaPlayer.getCurrentPosition();
                    binding.current.setText(timeConversion((long) current_pos));
                    binding.seekbar.setProgress((int) current_pos);
                    handlerProgressBar.postDelayed(this, 1000);
    
                    Log.e(LOG_TAG, "11111");
                } catch (IllegalStateException ed) {
                    ed.printStackTrace();
                }
            }
        };
        handlerProgressBar.postDelayed(runnable, 1000);
    }
    
    0 讨论(0)
提交回复
热议问题