好的,所以最初我认为问题是每次按停止然后启动时,都会创建一个新的可运行对象,因此我们将同时运行多个可运行对象,因此每次更新计时器的速度都越来越快。但这似乎不是问题所在:我通过添加一个布尔值“ running”来更改代码,以便按开始/停止键仅更改布尔值变量。这样,我认为只有一个可运行对象正在运行。但是当我连续单击“开始/停止”几次时,它仍然变得更快。有人可以告诉我问题出在哪里吗?

package com.example.timernew;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    Handler h=new Handler();
    TextView t;
    Button start, stop,reset;
    boolean running;
    Runnable run=new Runnable() {
            @Override public void run() { updateTime(); } };;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        t = (TextView) findViewById(R.id.TextArea);
        start = (Button) findViewById(R.id.start_button);
        stop=(Button) findViewById(R.id.stop_button);
        running=false;
        h.post(run);

            start.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                if(running==false){
                running=true;
                }
            }
        });
        stop.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                if(running==true){
                running=false;
                }
            }
        });

    }
    public void updateTime() {
        if(running==true){
        t.setText("" + (Integer.parseInt(t.getText().toString()) +1));
        h.postDelayed(run, 1000);}
    }

}

最佳答案

我在“开始”按钮OnClickListenter中添加了对updateTime()的调用,并且点击停止后继续计数没有任何问题。即使在等待了10秒钟以上之后,再次点击“开始”仍会从中断处继续开始。

我确实注意到,如果我在到达停止点的1秒内达到开始值,则该值将连续快速增加两次。这是因为单击start会调用updateTime()并且先前发布的runnable的延迟尚未完成,所以当这样做时,它也会增加时间。

更好的选择是使用AsyncTask:

    package com.example.timernew;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    Handler h=new Handler();
    TextView t;
    Button start, stop,reset;
    volatile boolean running;
    UpdateTimeTask mUpdateTimeTask;
    int counter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        t = (TextView) findViewById(R.id.TextArea);
        start = (Button) findViewById(R.id.start_button);
        stop=(Button) findViewById(R.id.stop_button);
        running=false;

        start.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                if (null == mUpdateTimeTask) {
                    mUpdateTimeTask = new UpdateTimeTask();
                    mUpdateTimeTask.execute();
                }
            }
        });

        stop.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                if(null != mUpdateTimeTask) {
                    mUpdateTimeTask.cancel(true);
                    mUpdateTimeTask = null;
                }
            }
        });

    }

    public class UpdateTimeTask extends AsyncTask<Void, Void, Void> {

        protected Void doInBackground(Void... params) {

            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                    Log.e("timer app", "a problem occurred while sleeping or the task was cancelled", ie);
                    return null;
                }
                counter++;
                publishProgress();
            }
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
            t.setText(String.valueOf(counter));
        }
    }
}


要回答有关更改布尔值并调用updateTime()的问题:

在您的原始代码中,仅在以下行的onCreate()期间调用updateTime():

h.post(run);


并且由于您将布尔值设置为false,因此它什么也不做,就可以完成运行。

现在,假设您将调用添加到start_button Click侦听器内的updateTime()上,并依次单击开始,停止和全部启动。这是正在发生的事情(假设这些事件每隔100ms发生一次):

0毫秒
单击开始将布尔值设置为true,调用updateTime()

10毫秒
调用updateTime(),布尔值为true,因此它更改文本并发布一个可运行时间为1000ms

100毫秒
单击停止将布尔值设置为false

200毫秒
单击开始将布尔值设置为true,调用updateTime()

210毫秒
调用updateTime(),布尔值为true,因此它更改文本并发布一个可运行时间为1000ms

1010毫秒
第一个发布的runnable运行,看到布尔值是true,更改文本并发布另一个在1000ms内运行的runnable

1210毫秒
第二次发布runnable运行,看到布尔值为true,更改文本,并发布另一个runnable

此时,您的时间不到1.3秒,而计数已经是3秒。现在,此后大约每n + .1和n + .2秒更改一次文本。

09-15 20:04