好的,所以最初我认为问题是每次按停止然后启动时,都会创建一个新的可运行对象,因此我们将同时运行多个可运行对象,因此每次更新计时器的速度都越来越快。但这似乎不是问题所在:我通过添加一个布尔值“ 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秒更改一次文本。