Android(如何在手机旋转后阻止创建新线程)

贵有恒,何必三更起、五更眠、最无益,只怕一日曝、十日寒。这篇文章主要讲述Android:如何在手机旋转后阻止创建新线程相关的知识,希望能为你提供帮助。
【Android(如何在手机旋转后阻止创建新线程)】我写了一个android程序来检测房间是否嘈杂或相当。但每当我旋转手机时,短信和图像都不会再更新,并且会打印噪音分贝 - 无穷大及其正确值。我认为每次旋转手机时都会创建一个新线程。因为如果我旋转手机,则会再次打印amplitudeDb数量值 - 无穷大。我怎样才能防止这种情况发生?每次旋转手机时,如何在没有生成新线程的情况下保持初始线程运行?
这是我的代码

public class EnvironmentalNoise extends AppCompatActivity {Context mContext; private MediaRecorder mRecorder = null; double soundLevel; SoundMeter sm; ImageView noiseImage; TextView noiseTv; double amplitudeDb; boolean mediaRecorderExist; boolean isTreadRunning; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_environmental_noise); noiseImage = findViewById(R.id.noiseImage); noiseTv = findViewById(R.id.noiseTv); mContext = getApplicationContext(); PackageManager PM= this.getPackageManager(); sm = new SoundMeter(); final boolean microphone = PM.hasSystemFeature(PackageManager.FEATURE_MICROPHONE); amplitudeDb =0; mediaRecorderExist = false; isTreadRunning =false; if (microphone){ sm.start(); } else{ noiseTv.setText("Sorry !!! This device is not equipped to microphone to detect environmental noise"); }}@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d("SaveState", "onSaveInstanceState called"); //save current amplitudeDb value in bundle key - value outState.putDouble("SAVED_STATE_COUNT_KEY", amplitudeDb); outState.putBoolean("MEDIA_RECORDER_EXIST",mediaRecorderExist); }@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); Log.d("SaveState", "onRestoreInstanceState called"); //retrieve current counter value from bundle based on key int retrievedNoiseDecibel = savedInstanceState.getInt("SAVED_STATE_COUNT_KEY"); boolean retrievedMediaRecorder = savedInstanceState.getBoolean("MEDIA_RECORDER_EXIST"); if(retrievedMediaRecorder){ retrievedMediaRecorder = false; }//update text view if(retrievedNoiseDecibel> 60){ noiseTv.setText("This room is noisy!!!"); noiseImage.setBackgroundResource(R.drawable.noise); } else{ noiseTv.setText("This room is quiet!!!"); noiseImage.setBackgroundResource(R.drawable.quiet); }Log.d("SaveState", "retrieved counter value:" + retrievedNoiseDecibel); //Toast.makeText(this, "retrieved counter value:" + retrievedCounter, Toast.LENGTH_LONG).show(); amplitudeDb = retrievedNoiseDecibel; //update total number of clicks mediaRecorderExist = retrievedMediaRecorder; }//start of refrencing // found this piece of code from here : https://stackoverflow.com/questions/31305163/getmaxamplitude-always-returns-0 public class SoundMeter {private MediaRecorder mRecorder = null; public void start() { if(mediaRecorderExist){ mRecorder.stop(); mRecorder.release(); mRecorder = null; } if (mRecorder == null) { mRecorder = new MediaRecorder(); mediaRecorderExist =true; mRecorder.setAudiosource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); Timer timer = new Timer(); //timer.schedule(new EnvironmentalNoise.RecorderTask(mRecorder), 0); timer.scheduleAtFixedRate(new RecorderTask(mRecorder), 0, 500); mRecorder.setOutputFile("/dev/null"); try { mRecorder.prepare(); mRecorder.start(); } catch (IOException e) { e.printStackTrace(); } catch (RuntimeException e){ e.printStackTrace(); } } }private class RecorderTask extends TimerTask { //TextView sound = (TextView) findViewById(R.id.decibel); private MediaRecorder recorder; public RecorderTask(MediaRecorder recorder) { this.recorder = recorder; }public void run() { runOnUiThread(new Runnable() { @Override public void run() { int peakAmplitude = recorder.getMaxAmplitude(); //double amplitudeDb = 20 * Math.log10((double)Math.abs(peakAmplitude)); amplitudeDb = 20 * Math.log10((double)Math.abs(peakAmplitude)); Log.i("sound","amplitudeDb" + amplitudeDb); if (amplitudeDb> 60){ noiseTv.setText("This room is noisy!!!"); noiseImage.setBackgroundResource(R.drawable.noise); } else{ noiseTv.setText("This room is quiet!!!"); noiseImage.setBackgroundResource(R.drawable.quiet); } } }); } } }// end of referencing

答案你可以在AndroidManifest中为这个活动添加android:configChanges =“orientation | screenSize”。在这种情况下,不会重新创建活动,并且不会再次创建线程
另一答案设置android:configChanges="orientation|screenSize"有效(在你的情况下),但不是一个好的解决方案,而不是它应该做的惯用方式。
这是因为如果您具有不同的纵向和横向布局,则在旋转手机时将无法正确加载它们。
以下是一些选项:
  1. 做@toshkinl建议并使用服务。这样做的好处是即使应用程序关闭,Thread也会运行。但是,这可能超出了您的应用范围。
  2. 将线程放在Application类中并在活动中访问它: MyApplication app = (MyApplication) getApplication(); 这样做的好处是它易于实现,并且您的线程将在配置更改和更改活动后继续存在。请注意,Android操作系统可以在未使用时终止您的应用程序,因此当您的应用程序重新启动时,应用程序类中的线程引用将设置为null,在这种情况下,您只需重新创建线程。

    推荐阅读