【问题标题】:Mediaplayer progress update to seekbar not smooth?Mediaplayer 进度更新到 seekbar 不顺畅?
【发布时间】:2013-07-18 12:37:21
【问题描述】:

我正在开发一个带有录音机和播放器的应用程序。我正在使用 mediaplayer 播放录制的 .wav 文件,同时我想更新到搜索栏。一切正常但我的问题是媒体播放器对搜索栏的进度更新并不顺利,如果我们正在播放一个小文件,搜索栏的拇指会在几秒钟内或之间跳跃。

任何人都可以帮助我解决问题,以使其在搜索栏中顺利搜索进度。我的代码如下所示。我被卡在这里了。

    mediaPlayerIntiate();
    mediaPlayerSetSource();
    mMediaPlayer.start();
    task = new TimerTask() {
                @Override
                public void run() {
                    Graphbar.post(new Runnable() {
                        @Override
                        public void run() {

                            if (mMediaPlayer != null) {

                                if (playButtonState == MediaMode.PLAY) {
                                    if (mMediaPlayer.isPlaying()) {
                                        Graphbar.setProgress(mMediaPlayer
                                                .getCurrentPosition());
                                        mediaPlayerUpdateTimer(mMediaPlayer
                                                .getCurrentPosition());
                                        enableRewindandForward();
                                    }
                                }

                            }

                        }
                    });
                }
            };
            timer = new Timer();
            timer.schedule(task, 0, 8);

【问题讨论】:

  • 如果记录的总持续时间小于某个值,您是否尝试过仅设置动画(使用属性动画)搜索栏而不是调用 mMediaPlayer.getCurrentPosition()?
  • 建议:不要在一秒钟内调用 new Runnable() 125 次。你做的垃圾太多了。
  • 你在什么设备上测试这个?我尝试了您的代码并且搜索栏更新顺利,即使1 第二次播放时间(在 nexus 4 上)。
  • 播放 .wav 文件时出现问题,请告诉我 1 秒 wav 文件如何在 ma 代码中工作。

标签: android media-player progress seekbar smooth


【解决方案1】:

mMediaPlayer.getCurrentPosition() 返回当前时间(以毫秒为单位),并将其更新为最大容量为 100 的 Seekbar。使用文件长度和 100 制作一个公式。试试这个函数

    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);

并且这个过程应该在媒体播放器开始播放时被调用。里面

    mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

        @Override
        public void onPrepared(MediaPlayer mp) {
        **// call here**
        }
    });

更新

在几秒钟内更新 125 次不是您应该做的事情。请增加更新 SeekBar 的间隔。我在阅读 NullPointer 的 cmets 后添加了这个

【讨论】:

  • 实际上我有以毫秒为单位播放音频文件的总持续时间,并且正在设置 Graphbar.setMax("totalduration");在播放之前到 seekbar...Seekbar max in millisec 和 progres 更新也以毫秒为单位,所以这不是问题...抱歉,ma 问题中缺少部分代码..:-)
  • 好的,那你可以试试Runnable来更新进度,不推荐使用Timer。它消耗内存泄漏
  • 我使用 runnable 来更新搜索栏,但它一点也不流畅。更新的时候咯咯地笑。所以我在做什么是我每秒更新搜索栏 125 次,是的,它帮助我使它变得平滑,但仍然存在抖动......它没有顺利进行
  • 好的,一旦看到这个例子androidtrainningcenter.blogspot.in/2012/09/…。尝试下载并运行,取消勾选ziddu上的标记,否则您将无法下载它
  • 我们应该在 onPreparedlistner 中调用 mediaplayer.start() 吗?或者我们也应该启动计时器??
【解决方案2】:

seekbar.setProgress() 只接受 int。因此,我们大多数人倾向于将经过的百分比传递给此方法。但是,如果您需要更平滑的进程,则可以使用以毫秒为单位的持续时间作为 MAX。然后我们每毫秒更新搜索栏的进度。下面是一个示例,我每 15 毫秒更新一次,因为几乎每部 Android 手机都具有 60 fps(每秒帧数)的刷新率。

    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;
}

【讨论】:

    【解决方案3】:

    这是我处理搜索栏的方式;

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

    现在我有一个名为 SeekBarHandler 的异步任务,它像这样处理搜索栏:

        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;
    }
    
        }
    

    现在在我的 onPause 中,我终止了 AsyncTask,因为当用户看不到搜索栏时保持线程继续运行是没有意义的

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

    在 onResume 上我像这样启动 AsyncTaskAgain

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

    如您所见,我使用布尔标志 isViewOn 来检查视图是否打开来处理搜索栏。

    【讨论】:

    • Thankzz 是的,这是有效的(不像我预期的那样)它正在播放媒体播放器时更新进度条......但是搜索栏的抖动仍然存在:-(..我需要更新它尽可能顺畅...支持我像您一样尝试另一种方式...非常感谢..但遗憾的是它仍然没有那么顺利..
    • 嗨 Sreedev,这是另一种尝试移动搜索栏的方法。我回来时写了这个答案,所以我不知道它是否仍然有效,但值得一试:stackoverflow.com/questions/9684302/…
    • If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask. developer.android.com/reference/android/os/AsyncTask.html 另外,AsyncTask 默认运行在 SERIAL_EXECUTOR 上,您可能希望在 THREAD_POOL_EXECUTOR 上执行它以确保其他任务不会被阻塞。
    【解决方案4】:
    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);
    

    【讨论】:

      【解决方案5】:

      您遇到的问题与 Android 的 SeekBar 的设计/实现方式有关。虽然它的功能非常好,但您会受到使用的段(即seekbar.setMax(int))和处理程序的延迟时间组合的限制。

      话虽如此,我将 SeekBar 子类化以制作我自己的 SmoothSeekBar,它使用 ViewPropertyAnimators 而不是 Handler。

      在这里查看:https://github.com/Indatus/Android-SmoothSeekBar

      【讨论】:

        【解决方案6】:
        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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-10-18
          • 2017-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多