CountDownTimer在尝试重播声音时冻结UI

时间:2019-02-11 18:15:18

标签: java android countdowntimer

我正在尝试每秒从3到1再现beep.wav声音,例如,再现3、2和1的哔声,然后在完成时再现哔声。

由于某种原因,只有蜂鸣声正在播放,但是当到达第二秒3时,用户界面似乎冻结了一秒钟,然后数字迅速减小到0

private void stopPlaying(){
        if(mp!=null){
            try {
                mp.reset();
                mp.prepareAsync();
                mp.stop();
                mp.release();
                mp=null;
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    private void startCountDown() {

        aCounter = new CountDownTimer(10000, 100) {
            public void onTick(long millisUntilFinished) {


                if (Math.round((float) millisUntilFinished / 1000.0f) != secondsLeft) {
                    countDownTxt.setTextColor(getResources().getColor(R.color.white));
                    secondsLeft = Math.round((float) millisUntilFinished / 1000.0f);
                    countDownTxt.setText(String.valueOf(secondsLeft));
                }

                if (secondsLeft <= 3) {
                    countDownTxt.setTextColor(getResources().getColor(R.color.colorAccent));
                    stopPlaying();
                    mp = MediaPlayer.create(MainActivity.this, R.raw.beep);
                    mp.start();
                }
            }

            public void onFinish() {
                secondsLeft = 0;
                stopPlaying();
                mp = MediaPlayer.create(MainActivity.this, R.raw.beepend);
                mp.start();
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        aCounter.cancel();
                        startCountDown();
                    }
                }, 1000);

            }
        };
        aCounter.start();
    }

我认为它可以如上所述工作,有什么提示吗?

1 个答案:

答案 0 :(得分:1)

MediaPlayer.create()可能是一个非常昂贵的电话。考虑一下如果花费大约100毫秒(甚至更多)会发生什么:

  1. 计时器调用onTick()
  2. onTick()MediaPlayer.create()内部阻塞约100毫秒。
  3. mp开始播放,然后onTick()返回。 (到目前为止,太好了!)
  4. 计时器立即意识到另一个onTick()通话到期了!最后一个开始于100毫秒前!
  5. onTick()几乎立即被再次调用。很快,它到达了stopPlaying()调用。但是您只有开始在大约1毫秒前播放!

这会导致您的计时器将所有时间都花在MediaPlayer.create()上,而实际上没有时间播放声音。

请注意,在编写代码的情况下,它将在倒数的最后3秒内尝试播放声音大约30次(因为刻度线之间最好间隔100毫秒)。如果您打算只播放声音3次,则可能需要将第二个if块移到第一块的内部。这样,您仅在secondsLeft实际更改时尝试播放。这实际上将改善原始问题,并且您可能不需要任何进一步的更改。

但是,如果您想进一步优化,请注意,您可以预先准备mp(例如,在应用启动时)并简单地重用它:而不是release()-对其进行分别时间,只需stop()prepare()(并且不要 reset())。这样就可以为下一场比赛做好准备了。您甚至可以仅为MediaPlayer创建一个单独的beepend,并且可以在应用初始化期间同时准备它们。