简体   繁体   English

什么是在android中停止线程的好方法

[英]what is a good way to stop a thread in android

I am trying to passthrough the input obtained from the microphone to the speaker (the goal is to be able to perform audio processing in real time in the future). 我正在尝试将从麦克风获得的输入传递给扬声器(目标是将来能够实时执行音频处理)。 This is the code: 这是代码:

public class MainActivity extends Activity {
    AudioManager am = null;
    AudioRecord record =null;
    AudioTrack track =null;
    final int SAMPLE_FREQUENCY = 44100;
    final int SIZE_OF_RECORD_ARRAY = 1024;  // 1024 ORIGINAL
    final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
    int i= 0;
    boolean isPlaying = true;
    class MyThread extends Thread{
        @Override
        public void run(){
            recordAndPlay();
        }
    }

    MyThread newThread;

    private void init() {
        int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
        record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
                                 AudioFormat.ENCODING_PCM_16BIT, min);
        int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
                               AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
     }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
        init();
        newThread = new MyThread();
        newThread.start();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private void recordAndPlay() {
        short[] lin = new short[SIZE_OF_RECORD_ARRAY];
        int num = 0;
        am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
        am.setMode(AudioManager.MODE_IN_COMMUNICATION);
        record.startRecording();
        track.play();
        while (true) {
            num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
            for(i=0;i<lin.length;i++)
                lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR; 
            track.write(lin, 0, num);
        }
    }

    public void passStop(View view){
        Button playBtn = (Button) findViewById(R.id.playBtn);  
        // /*
        if(!isPlaying){
            record.startRecording();
            track.play();
            isPlaying = true;
            playBtn.setText("Pause");
        }
        else{
           record.stop();
           track.pause();
           isPlaying=false;
           playBtn.setText("Pass through");
        }
        // */
    }

/*
    @SuppressWarnings("deprecation")
    @Override
    public void onDestroy(){
        newThread.stop();
    }
    */

    @Override
    protected void onDestroy() {
        android.os.Process.killProcess(android.os.Process.myPid());
        // killProcess(android.os.Process.myPid());
    }
}  

Brief overview: 简要概述:
The while(true) {} infinite loop in recordAndPlay() function continuously reads raw audio samples from the microphone and outputs the raw samples to the speaker. recordAndPlay()函数中的while(true) {}无限循环不断从麦克风读取原始音频样本,并将原始样本输出到扬声器。 recordAndPlay() is called from a Thread started in the onCreate() function. onCreate()函数中启动的线程中调用recordAndPlay() So it starts sending the input on the microphone to the speaker as soon as the program starts (well actually after a few seconds lag but I think this latency in unavoidable). 因此,它会在程序启动后立即将麦克风上的输入发送到扬声器(实际上是在几秒钟的延迟之后,但是我认为这种延迟是不可避免的)。 I also have a button that can pause and resume this pass through. 我也有一个按钮,可以暂停和继续此过程。 Now if the Thread is not stopped, the pass through continues even when I exit the application or the application looses focus (so even when the phone is on the desktop it keeps doing the passthrough). 现在,如果线程没有停止,即使我退出应用程序或应用程序失去焦点,传递仍会继续(因此即使手机在桌面上,它也会继续传递)。

@SuppressWarnings("deprecation")
@Override
public void onDestroy(){
    newThread.stop();
}  

This code causes the app to crash on exit ( Why? ) so I used 此代码导致应用在退出时崩溃( 为什么? ),所以我使用了

@Override
protected void onDestroy() {
    android.os.Process.killProcess(android.os.Process.myPid());
    // killProcess(android.os.Process.myPid());
}  

that I found somewhere in stackoverflow (I forgot where). 我在stackoverflow的某个地方发现了(我忘了在哪里)。 It seems to do what I want for now, but I want know if this is the proper way to stop the Thread or not. 它似乎正在执行我现在想要的操作,但是我想知道这是否是停止线程的正确方法。 It does what I need, that is, it stops the passthrough when I exit the application, but I am not sure what exactly the killProcess() function does to my application overall, and if it is the best way to stop a Thread that I started myself. 它完成了我需要的操作,也就是说,当我退出应用程序时它会停止传递,但是我不确定killProcess()函数对我的应用程序到底有什么作用,以及这是否是停止线程的最佳方法。开始我自己。

Also, I can get the same effect if I exit my application (or loose focus to it) while the passthrough is being paused. 另外,如果我在暂停通行证时退出应用程序(或对其失去关注),也会获得相同的效果。 But I assume this means the Thread is still running which means the infinite loop is also continuously running as well. 但是我认为这意味着线程仍在运行,这意味着无限循环也正在持续运行。 Is it a good idea to do this, that is, just leave the Thread running, as long as my overall program is behaving as I want it to? 这是一个好主意吗,就是说,只要我的整体程序按我的意愿运行,就让Thread运行? What if I have lots of Threads or other background processes running? 如果我正在运行许多线程或其他后台进程怎么办? Can this practice cause memory problems in the future if the app grows too big? 如果应用程序太大,这种做法将来是否会导致内存问题?

Threads should periodically check for some shouldTerminate flag in their loop, then just set this flag from UI thread and (optionally) wait until thread terminate gracefully. 线程应定期检查其循环中是否有某些shouldTerminate标志,然后只需在UI线程中设置此标志,然后(可选)等待直到线程正常终止为止。 Don't forget volatile or proper field synchronization. 不要忘记volatile或适当的字段同步。

Please remember to call super.onDestroy after releasing your memory or finishing the thread. 释放内存或完成线程处理后,请记住要调用super.onDestroy Otherwise it will throw Exception : 否则会抛出Exception

@Override
protected void onDestroy() {
    // You code here to finish the thread
    super.onDestroy(); // Please call THIS too
}

Hope this helps. 希望这可以帮助。

Change your Thread class to something like this: 将您的Thread类更改为如下所示:

class MyThread extends Thread {

    private volatile boolean finished = false;

    @Override
    public void run() {

        while (!finished) {
            // do stuff on thread
        }

    }

    public void stopThread() {
        finished = true;
    }

}

In your onDestroy method call stopThread(). 在您的onDestroy方法中,调用stopThread()。

@Override
protected void onDestroy() {
    newThread.stopThread();
    super.onDestroy();
}

If you wish, you can also wait for thread to stop, by using this method: 如果愿意,还可以使用以下方法等待线程停止:

    private void joinThread(Thread thread) {
        boolean retry = true;
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                // to be handled as you wish
            }
        }
    }

Put this method in your activity and call it after newThread.stopThread() . 将此方法放在您的活动中,并在newThread.stopThread()之后调用它。

There is already a provided flag for interuption. 已经提供了用于中断的标志。 Correct your while loop to the following. 将while循环更正为以下内容。 And just call interupt(); 然后调用interupt(); in onDestroy or wherever. 在onDestroy或任何地方。

private class thrd extends Thread {

    @Override
    public void run() {
        super.run();
        while (!isInterrupted()) {
            //TODO
        }
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    thrd.interupt();
}

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

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