为什么我的秒表Android应用程序中的onStop和onStart方法不能正常工作?

问题描述

通过单击“开始”按钮来启动秒表。

我可以通过按下设备上的主页按钮来隐藏“活动”。

但是根据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);

                }
            });

        }

    }