为什么我的 onStop() 和 onStart() 方法在我的秒表 Android 应用程序中无法正常协同工作?
Why my onStop() and onStart() methods work not correctly together in my stopwatch Android app?
通过单击“开始”按钮启动秒表。
我通过按下设备上的主页按钮使 Activity 不可见。
但是根据 onStop() 方法,秒表计时不会停止:因为当 activity 再次可见时,秒表计数看起来从未停止过(数字继续增加非-尽管使用 onStop() 方法仍处于焦点状态。
但是,如果我删除了 onStart() 方法,则在按下家庭设备按钮后,根据 onStop(),计时会正确停止。
秒表本身计数正确,计时准确。
只有可见-不可见,停止-启动时序问题,onStop() - onStart()方法交互。
我尝试组合 onPause() - onResume(),包括 onRestart() 和
依此类推,但结果是一样的
我的代码有什么问题?
如果能提供帮助,我将不胜感激
package com.example.stopwatch;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import java.lang.System;
import java.util.Locale;
public class StopwatchActivity extends Activity {
//Number of seconds in stopwatch.
private int milliseconds = 0;
//Indicates whether a stopwatch is running.
private boolean running;
// Presents time in millis, when the click on Start button is executed.
private int startMillis;
// Shows whether the stopwatch was running when activity became invisible.
private boolean wasRunning;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_stopwatch);
if(saveInstanceState != null) {
milliseconds = saveInstanceState.getInt("milliseconds");
running = saveInstanceState.getBoolean("running");
wasRunning = saveInstanceState.getBoolean("wasRunning");
startMillis = saveInstanceState.getInt("startMillis");
}
runTimer();
}
@Override
public void onSaveInstanceState(Bundle saveInstanceState) {
saveInstanceState.putInt("milliseconds", milliseconds);
saveInstanceState.putBoolean("running", running);
saveInstanceState.putBoolean("wasRunning", wasRunning);
saveInstanceState.putInt("startMillis", startMillis);
}
@Override
protected void onStop() {
super.onStop();
wasRunning = running;
running = false;
}
@Override
protected void onStart() {
super.onStart();
if (wasRunning) {
running = true;
}
}
//Run the stopwatch on a Start button click.
public void onClickStart(View view) {
running = true;
startMillis = (int)System.currentTimeMillis();
}
//Stop the stopwatch on a Stop button click.
public void onCLickStop(View view) {
running = false;
}
//Reset the stopwatch on a Reset button click.
public void onClickReset(View view) {
running = false; milliseconds = 0;
}
private void runTimer() {
final TextView timeView = (TextView)findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
int minutes = (int)((milliseconds%3600000)/60000);
int secs = (int)((milliseconds%60000)/1000);
int msecs = milliseconds%1000;
String time = String.format(Locale.getDefault(),
"%02d:%02d:%03d", minutes, secs, msecs);
timeView.setText(time);
if (running) {
milliseconds = (int)(System.currentTimeMillis()-startMillis);
}
handler.postDelayed(this, 1);
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.example.stopwatch.StopwatchActivity">
<TextView
android:id="@+id/time_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="@android:style/TextAppearance.Large"
android:textSize="56sp" />
<Button
android:id="@+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:onClick="onClickStart"
android:text="@string/start" />
<Button
android:id="@+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:onClick="onCLickStop"
android:text="@string/stop" />
<Button
android:id="@+id/reset_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:onClick="onClickReset"
android:text="@string/reset" />
</LinearLayout>
至少有两个问题:
- 假设您对该表达式求值两次,这样第二次求值将在时间轴中第一次求值后 5 秒:
milliseconds = (int)(System.currentTimeMillis()-startMillis);
因此,milliseconds
价值总是随着时间的推移而增加!这意味着即使用户按下开始按钮,等待 2 秒,按下停止按钮,等待 3 秒,按下开始按钮,milliseconds
值将等于秒表开始计时时的 5,而不是2 如你所愿!
- 您应该知道,当用户使用另一个应用程序时,您代码库中
Runnable
中的代码不会停止。因此,您应该以某种方式阻止此代码执行,因为当代码在不应该执行时执行时,用户体验很差。
谢谢 Николай Γольцев 的指教!
我解决了问题:
我通过添加新变量 (saveMillis) 更改了在方法 运行() 中评估毫秒的表达式。 «点击方法»也有一些变化。下面的代码现在运行良好
package com.example.stopwatch;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import java.lang.System;
import java.util.Locale;
public class StopwatchActivity extends Activity {
//Number of seconds in stopwatch.
private int milliseconds = 0;
//Indicates whether a stopwatch is running.
private boolean running;
// Presents time in millis, when the click on Start button is executed.
private int startMillis;
// Shows whether the stopwatch was running when activity became invisible.
private boolean wasRunning;
//Save the current time in milliseconds, when the timing is stopped.
private int saveMillis = 0;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_stopwatch);
if (saveInstanceState != null) {
milliseconds = saveInstanceState.getInt("milliseconds");
running = saveInstanceState.getBoolean("running");
wasRunning = saveInstanceState.getBoolean("wasRunning");
startMillis = saveInstanceState.getInt("startMillis");
saveMillis = saveInstanceState.getInt("saveMillis");
}
runTimer();
}
@Override
public void onSaveInstanceState(Bundle saveInstanceState) {
saveInstanceState.putInt("milliseconds", milliseconds);
saveInstanceState.putBoolean("running", running);
saveInstanceState.putBoolean("wasRunning", wasRunning);
saveInstanceState.putInt("startMillis", startMillis);
saveInstanceState.putInt("saveMillis", saveMillis);
}
@Override
protected void onStop() {
super.onStop();
wasRunning = running;
running = false;
saveMillis = milliseconds;
}
@Override
protected void onStart() {
super.onStart();
if (wasRunning) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
}
//Run the stopwatch on a Start button click.
public void onClickStart(View view) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
//Stop the stopwatch on a Stop button click.
public void onCLickStop(View view) {
running = false;
saveMillis = milliseconds;
}
//Reset the stopwatch on a Reset button click.
public void onClickReset(View view) {
running = false;
milliseconds = 0;
saveMillis = 0;
}
//Resume timing.
public void onClickResume(View view) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
private void runTimer() {
final TextView timeView = (TextView) findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
int minutes = (int) ((milliseconds % 3600000) / 60000);
int secs = (int) ((milliseconds % 60000) / 1000);
int msecs = milliseconds % 1000;
String time = String.format(Locale.getDefault(),
"%02d:%02d:%03d", minutes, secs, msecs);
timeView.setText(time);
if (running) {
milliseconds = saveMillis + ((int) (System.currentTimeMillis() - startMillis));
}
handler.postDelayed(this, 1);
}
});
}
}
通过单击“开始”按钮启动秒表。
我通过按下设备上的主页按钮使 Activity 不可见。
但是根据 onStop() 方法,秒表计时不会停止:因为当 activity 再次可见时,秒表计数看起来从未停止过(数字继续增加非-尽管使用 onStop() 方法仍处于焦点状态。
但是,如果我删除了 onStart() 方法,则在按下家庭设备按钮后,根据 onStop(),计时会正确停止。
秒表本身计数正确,计时准确。
只有可见-不可见,停止-启动时序问题,onStop() - onStart()方法交互。
我尝试组合 onPause() - onResume(),包括 onRestart() 和 依此类推,但结果是一样的
我的代码有什么问题?
如果能提供帮助,我将不胜感激
package com.example.stopwatch;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import java.lang.System;
import java.util.Locale;
public class StopwatchActivity extends Activity {
//Number of seconds in stopwatch.
private int milliseconds = 0;
//Indicates whether a stopwatch is running.
private boolean running;
// Presents time in millis, when the click on Start button is executed.
private int startMillis;
// Shows whether the stopwatch was running when activity became invisible.
private boolean wasRunning;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_stopwatch);
if(saveInstanceState != null) {
milliseconds = saveInstanceState.getInt("milliseconds");
running = saveInstanceState.getBoolean("running");
wasRunning = saveInstanceState.getBoolean("wasRunning");
startMillis = saveInstanceState.getInt("startMillis");
}
runTimer();
}
@Override
public void onSaveInstanceState(Bundle saveInstanceState) {
saveInstanceState.putInt("milliseconds", milliseconds);
saveInstanceState.putBoolean("running", running);
saveInstanceState.putBoolean("wasRunning", wasRunning);
saveInstanceState.putInt("startMillis", startMillis);
}
@Override
protected void onStop() {
super.onStop();
wasRunning = running;
running = false;
}
@Override
protected void onStart() {
super.onStart();
if (wasRunning) {
running = true;
}
}
//Run the stopwatch on a Start button click.
public void onClickStart(View view) {
running = true;
startMillis = (int)System.currentTimeMillis();
}
//Stop the stopwatch on a Stop button click.
public void onCLickStop(View view) {
running = false;
}
//Reset the stopwatch on a Reset button click.
public void onClickReset(View view) {
running = false; milliseconds = 0;
}
private void runTimer() {
final TextView timeView = (TextView)findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
int minutes = (int)((milliseconds%3600000)/60000);
int secs = (int)((milliseconds%60000)/1000);
int msecs = milliseconds%1000;
String time = String.format(Locale.getDefault(),
"%02d:%02d:%03d", minutes, secs, msecs);
timeView.setText(time);
if (running) {
milliseconds = (int)(System.currentTimeMillis()-startMillis);
}
handler.postDelayed(this, 1);
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.example.stopwatch.StopwatchActivity">
<TextView
android:id="@+id/time_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="@android:style/TextAppearance.Large"
android:textSize="56sp" />
<Button
android:id="@+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:onClick="onClickStart"
android:text="@string/start" />
<Button
android:id="@+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:onClick="onCLickStop"
android:text="@string/stop" />
<Button
android:id="@+id/reset_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:onClick="onClickReset"
android:text="@string/reset" />
</LinearLayout>
至少有两个问题:
- 假设您对该表达式求值两次,这样第二次求值将在时间轴中第一次求值后 5 秒:
milliseconds = (int)(System.currentTimeMillis()-startMillis);
因此,milliseconds
价值总是随着时间的推移而增加!这意味着即使用户按下开始按钮,等待 2 秒,按下停止按钮,等待 3 秒,按下开始按钮,milliseconds
值将等于秒表开始计时时的 5,而不是2 如你所愿!
- 您应该知道,当用户使用另一个应用程序时,您代码库中
Runnable
中的代码不会停止。因此,您应该以某种方式阻止此代码执行,因为当代码在不应该执行时执行时,用户体验很差。
谢谢 Николай Γольцев 的指教!
我解决了问题:
我通过添加新变量 (saveMillis) 更改了在方法 运行() 中评估毫秒的表达式。 «点击方法»也有一些变化。下面的代码现在运行良好
package com.example.stopwatch;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import java.lang.System;
import java.util.Locale;
public class StopwatchActivity extends Activity {
//Number of seconds in stopwatch.
private int milliseconds = 0;
//Indicates whether a stopwatch is running.
private boolean running;
// Presents time in millis, when the click on Start button is executed.
private int startMillis;
// Shows whether the stopwatch was running when activity became invisible.
private boolean wasRunning;
//Save the current time in milliseconds, when the timing is stopped.
private int saveMillis = 0;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_stopwatch);
if (saveInstanceState != null) {
milliseconds = saveInstanceState.getInt("milliseconds");
running = saveInstanceState.getBoolean("running");
wasRunning = saveInstanceState.getBoolean("wasRunning");
startMillis = saveInstanceState.getInt("startMillis");
saveMillis = saveInstanceState.getInt("saveMillis");
}
runTimer();
}
@Override
public void onSaveInstanceState(Bundle saveInstanceState) {
saveInstanceState.putInt("milliseconds", milliseconds);
saveInstanceState.putBoolean("running", running);
saveInstanceState.putBoolean("wasRunning", wasRunning);
saveInstanceState.putInt("startMillis", startMillis);
saveInstanceState.putInt("saveMillis", saveMillis);
}
@Override
protected void onStop() {
super.onStop();
wasRunning = running;
running = false;
saveMillis = milliseconds;
}
@Override
protected void onStart() {
super.onStart();
if (wasRunning) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
}
//Run the stopwatch on a Start button click.
public void onClickStart(View view) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
//Stop the stopwatch on a Stop button click.
public void onCLickStop(View view) {
running = false;
saveMillis = milliseconds;
}
//Reset the stopwatch on a Reset button click.
public void onClickReset(View view) {
running = false;
milliseconds = 0;
saveMillis = 0;
}
//Resume timing.
public void onClickResume(View view) {
running = true;
startMillis = (int) System.currentTimeMillis();
}
private void runTimer() {
final TextView timeView = (TextView) findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
int minutes = (int) ((milliseconds % 3600000) / 60000);
int secs = (int) ((milliseconds % 60000) / 1000);
int msecs = milliseconds % 1000;
String time = String.format(Locale.getDefault(),
"%02d:%02d:%03d", minutes, secs, msecs);
timeView.setText(time);
if (running) {
milliseconds = saveMillis + ((int) (System.currentTimeMillis() - startMillis));
}
handler.postDelayed(this, 1);
}
});
}
}