处理程序在可运行任务中的while循环处理期间冻结UI [安卓]

3

我希望重复录制 - - - 等等。当录音的能量达到某个阈值时,录制(以秒为单位)将停止并开始播放。播放后,会开始新的录制。因此,我需要使用缓冲区监视能量,并在计算播放时间后开始新的录制。我的伪代码(最简化形式)如下:

...

public class MainActivity extends Activity {
    private Handler myHandler = new Handler();

....

    private Runnable timedTask = new Runnable() {
        public void run() {
           audiorecorder = new AudioRecord(...  initializes
           audiorecorder.startRecording();
           isRecording = true; 
           ElapsedTime = 0.0;
           while(true) {
                ReadByte = audiorecorder.read(buffer, 0, buffersize);
                // Write ReadByte onto file (temp.pcm)

                EnergyBuffer = <some averaged energy over a period (1 sec or so)>
                if(EnergyBuffer > Threshold)
                     break;
                ElapsedTime = ...
           }
           // audiorecorder.release, stop, and null
           // play temp.pcm using AudioTrack           

           myHandler.postDelayed(timedTask, Elapsedtime);
    };
}

这是通过以下的开始和停止按钮触发的:
    StartButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            myHandler.post(timedTask);
        }
    });

    StopButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            myHandler.removeCallbacks(timedTask);
        }
    });

问题是在录制或播放音频时,没有任何按钮可以使用,我必须等到录制完成才能操作。我该如何避免录制冻结?这是否只是由于while循环引起的?请帮忙解决..!
如果我按以下方式运行,则不会出现错误。
Thread t = new Thread(timedTask);
t.start();

这只有一次是可以的,但在处理程序延迟时间后,它也会冻结用户界面。

请展示如何定义myHandler。 - SilverCorvus
2个回答

6

一个处理程序将可运行任务发布到线程中的循环器。它本身不会创建一个新的线程,以便异步地运行可运行对象。

当您通过调用构造函数 new Handler() 创建处理程序时,默认情况下,处理程序将获取调用该构造函数的当前线程的循环器。由于您在UI线程上调用了 new Handler(),因此传递给处理程序的 post 命令的任何可运行命令都将添加到UI线程。

您需要创建一个新的线程并获取其循环器,方法如下:

HandlerThread readThread = new HandlerThread("");
readThread.start();
myHandler = new Handler(readThread.getLooper());

HandlerThread是一个可以自动为你设置looper的线程。

当然,一旦你不需要它了,你也需要退出这个线程。

readThread.quit();

2
我想点赞,但由于我的声望不高,所以我不能。我会在不久的将来回来投票!谢谢! - ben Heo
@benHeo 我会为你完成这个任务。 - Elltz

1

你是个天才,做得非常好,正是我为之努力了数天的结果,非常感谢!这就是我问题的答案:

public class MainActivity extends Activity {
    private Handler myHandler;

....

    private Runnable timedTask = new Runnable() {
        public void run() {
           audiorecorder = new AudioRecord(...  initializes
           audiorecorder.startRecording();
           isRecording = true; 
           ElapsedTime = 0.0;
           while(true) {
                ReadByte = audiorecorder.read(buffer, 0, buffersize);
                // Write ReadByte onto file (temp.pcm)

                EnergyBuffer = <some averaged energy over a period (1 sec or     so)>
                if(EnergyBuffer > Threshold)
                     break;
                ElapsedTime = ...
           }
           // audiorecorder.release, stop, and null
           // play temp.pcm using AudioTrack           

           myHandler.postDelayed(timedTask, Elapsedtime);
    };
....
    protected void OnCreate(Bundle savedInstanceState) {
        ...
        HandlerThread readThread = new HandlerThread("");
        readThread.start();
        myHandler = new Handler(readThread.getLooper());
        ...
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接