为什么我的简单计时器应用程序每次暂停都会变得更快?

时间:2014-06-07 17:46:32

标签: java android

好的,所以最初我认为问题在于每次按下停止然后启动时,都会创建一个新的runnable,因此我们将同时运行多个runnable,从而每次都更快更快地更新计时器。但它似乎不是问题:我通过添加布尔“运行”来更改代码,以便按下启动/停止只更改布尔变量。通过这种方式,我认为只有一个runnable正在运行。但是当我连续几次点击开始/停止时它仍然会变得更快。有人能告诉我问题在哪里吗?

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);}
    }

}

1 个答案:

答案 0 :(得分:1)

我在开始按钮OnClickListenter中添加了对updateTime()的调用,并且在点击停止后计数继续没有问题。即使在等待10秒以上,再次点击开始只是从它停止的地方开始继续。

我确实注意到,如果我在击中停止后的1秒内开始,那么该值将连续快速增加两倍。这是因为点击开始调用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()的问题:

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

h.post(run);

由于您将布尔值设置为false,因此它不会执行任何操作并完成运行。

现在,假设你在start_button点击监听器中添加对updateTime()的调用,并快速连续点击start,stop,start all。这里发生了什么(假设每个发生的时间间隔为100毫秒):

0毫秒
click start将boolean设置为true,调用updateTime()

10ms的
调用updateTime(),boolean为true,因此它更改文本并发布runnable以便在1000ms内运行

100毫秒 click stop将布尔值设置为false

200毫秒 click start将boolean设置为true,调用updateTime()

210ms 调用updateTime(),boolean为true,因此它更改文本并发布runnable以便在1000ms内运行

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

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

此时你的进入时间不到1.3秒,计数已经是3秒。现在,文本将从现在开始大约每n + .1和n + .2秒更改一次。