简体   繁体   English

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

[英]Infinite loop stops app from responding. What to do?

I have written a small app that draws a circle on a surfaceview that is proportional to the amount of sound reaching the phones mic (the louder the sound the bigger the circle). 我编写了一个小应用程序,该应用程序在SurfaceView上绘制了一个圆,该圆与到达电话麦克风的声音量成正比(声音越大,圆越大)。

Everything is working fine. 一切正常。 I can start things going at the press of a button, but then I go into an infinite loop (by design). 按下按钮就可以开始工作,但随后进入无限循环(根据设计)。 This causes the UI to hang. 这会导致UI挂起。 I would like to arrange things so that my app runs and keeps responding to mic input but the UI is still responsi9ve (ie so I can press a button (the back button perhaps?) to stop the app.). 我想安排一些事情,使我的应用程序运行并继续响应麦克风输入,但UI仍然响应(即,我可以按一个按钮(也许是后退按钮?)来停止该应用程序。)

At the moment the app till android thinks it hasn't responded in a long time (ANR?) and puts up a message box so I can quit it. 目前,直到android认为该应用很长时间没有响应(ANR?)的应用,并显示了一个消息框,以便我退出。

How do I avoid this? 如何避免这种情况? I know I should use a new thread, but what is the simplest way? 我知道我应该使用一个新线程,但是最简单的方法是什么?

    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>

You can use a AsyncTask to handle the recorder buffer in background and not block the UI task: 您可以使用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) {
        }
    }
}

This may very well contain errors but give it a go: 这很可能包含错误,但可以尝试一下:

       Thread micThread;

       private void respondToMIC() {

           if (micThread == null) {
               micThread = new Thread(new micRunnable());
               micThread.start();
           } else {
               // if you want the same button to shut it down
               stopRespondingToMic();
           }

        }

       private void stopRespondingToMic() {
           if (micThread != null && micThread.isAlive()) {
               micThread.interrupt();
               micThread = null;
           }
       }

        @Override
        protected void onPause() {
            stopRespondingToMic();
        }

       private class micRunnable implements Runnable {

            @Override
            public void run() {
                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);
                }
            }
       }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM