问题描述
通过单击“开始”按钮来启动秒表。
我可以通过按下设备上的主页按钮来隐藏“活动”。
但是根据onStop()方法,秒表计时不会停止:由于再次看到活动时,秒表的计数看起来从未停止过(尽管在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)更改了在run()方法中计算毫秒的表达式。 “点击方法”也有一些更改。下面的代码现在可以正常工作了
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);
}
});
}
}