java - 无限循环停止应用程序响应。该怎么办?

标签 java android multithreading

我编写了一个小应用程序,它在表面 View 上绘制一个圆圈,该圆圈与到达手机麦克风的声音量成正比(声音越大,圆圈越大)。

一切正常。我可以按一下按钮开始工作,但随后我进入了无限循环(按设计)。这会导致 UI 挂起。我想安排一些事情,以便我的应用程序运行并持续响应麦克风输入,但 UI 仍然响应(也就是说,我可以按下一个按钮(也许是后退按钮?)来停止应用程序。)。

目前应用程序直到 android 认为它已经很长时间没有响应(ANR?)并提出一个消息框以便我可以退出它。

如何避免这种情况?我知道我应该使用新线程,但最简单的方法是什么?

    public class MainActivity extends ActionBarActivity {

        private static final int RECORDER_SAMPLERATE = 44100;
        private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
        private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
        private static final int BUFFSIZE = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
        private AudioRecord recorder = null;
        private SurfaceView mySurface;
        private static Handler handler;

        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mySurface = (SurfaceView) findViewById(R.id.surfaceView);
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, BUFFSIZE);
            recorder.startRecording();
        }

        private void respondToMIC() {

            Canvas myCanvas;
            Paint paint = new Paint();
            paint.setARGB(255, 255, 100, 100);

            short sData[] = new short[BUFFSIZE/2];
            while (true)
            {
                int read = recorder.read(sData, 0, BUFFSIZE/2);
                int min = 0;
                int max = 0;
                for (int j=0; j< read; j++)
                {
                    if (sData[j] < min) min = sData[j];
                    if (sData[j] > max) max = sData[j];
                }
                myCanvas = mySurface.getHolder().lockCanvas();
                myCanvas.drawColor(Color.WHITE);
                myCanvas.drawCircle(myCanvas.getWidth()/2, myCanvas.getHeight()/2, ((myCanvas.getHeight()/2)*Math.abs(max-min)/65000), paint);
                mySurface.getHolder().unlockCanvasAndPost(myCanvas);
            }
        }
    }

    <SurfaceView
        android:layout_width="fill_parent"
        android:layout_height="221dp"
        android:id="@+id/surfaceView"
        android:layout_gravity="center" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="surface"
        android:id="@+id/button3"
        android:onClick="respondToMIC"
        android:layout_gravity="center_horizontal|bottom" />

</FrameLayout>

最佳答案

您可以使用 AsyncTask 在后台处理记录器缓冲区而不阻塞 UI 任务:

public class MainActivity extends ActionBarActivity {

    private static final int RECORDER_SAMPLERATE = 44100;
    private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
    private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    private static final int BUFFSIZE = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
    private AudioRecord recorder = null;
    private SurfaceView mySurface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mySurface = (SurfaceView) findViewById(R.id.surfaceView);
        recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, BUFFSIZE);
        recorder.startRecording();
    }

    private void respondToMIC() {
        new AudioRecordTask().execute();
    }

    private class AudioRecordTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            Canvas myCanvas;
            Paint paint = new Paint();
            paint.setARGB(255, 255, 100, 100);

            short sData[] = new short[BUFFSIZE / 2];

            // Run while the Activity is not finished.
            while (!isFinishing()) {
                int read = recorder.read(sData, 0, BUFFSIZE / 2);
                int min = 0;
                int max = 0;
                for (int j = 0; j < read; j++) {
                    if (sData[j] < min) min = sData[j];
                    if (sData[j] > max) max = sData[j];
                }
                myCanvas = mySurface.getHolder().lockCanvas();
                myCanvas.drawColor(Color.WHITE);
                myCanvas.drawCircle(myCanvas.getWidth() / 2, myCanvas.getHeight() / 2, ((myCanvas.getHeight() / 2) * Math.abs(max - min) / 65000), paint);
                mySurface.getHolder().unlockCanvasAndPost(myCanvas);
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

关于java - 无限循环停止应用程序响应。该怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20060219/

相关文章:

java - 具有循环泛型依赖项的泛型类型的编译错误

c# - 使用 C# 的线程池问题

java - Realm 中的@LinkingObjects 注解是如何工作的

android - 动画相对布局以像 Snack Bar 一样向下/向上移动

android - 使用哪些 API 来覆盖其他应用程序(例如 Facebook 的 Chat Heads)?

android - 启动谷歌地图 Intent 后返回 Activity

c++ - 如何处理多个线程的重复启动?

C# 线程方法名称预期错误

JavaCC:嵌套 for 循环

java - 将对象强制转换为类的类型安全方法