贵有恒,何必三更起、五更眠、最无益,只怕一日曝、十日寒。这篇文章主要讲述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"
有效(在你的情况下),但不是一个好的解决方案,而不是它应该做的惯用方式。这是因为如果您具有不同的纵向和横向布局,则在旋转手机时将无法正确加载它们。
以下是一些选项:
- 做@toshkinl建议并使用服务。这样做的好处是即使应用程序关闭,Thread也会运行。但是,这可能超出了您的应用范围。
- 将线程放在
Application
类中并在活动中访问它:MyApplication app = (MyApplication) getApplication();
这样做的好处是它易于实现,并且您的线程将在配置更改和更改活动后继续存在。请注意,Android操作系统可以在未使用时终止您的应用程序,因此当您的应用程序重新启动时,应用程序类中的线程引用将设置为null
,在这种情况下,您只需重新创建线程。
推荐阅读
- 如何在Activity中使用Retrofit和RxJava / RxAndroid处理旋转()
- Android(ImageView旋转动画 - 保持比例类型适合中心)
- Android(围绕Y的第二次180度旋转镜像会反映图像)
- 试图在android中旋转布局,画布似乎不会旋转
- Android两指旋转
- 如何在Android中旋转位图,使图像中心平滑,无振荡运动
- Android Camera2预览偶尔会旋转90度
- Android以XML格式访问SDK属性
- 如何解决Windows中的cmd或node.js命令提示符问题(git未安装或未在PATH中)