测验 android 应用程序的倒数计时器
countdown timer on a quiz android app
我正在尝试做一个简单的练习测验。我在添加倒数计时器时遇到问题。如果没有问题被回答,它工作正常,但当我回答问题时(即使它是正确的或错误的),计时器不会重置。我在 developer.android.com 上看到有 cancel() 方法,但我无法使它工作。有帮助吗?
这是我的代码。 (欢迎任何关于更好代码的建议,但我尽量保持简单,因为我是 android 开发的新手)。
public class QuizActivity extends Activity implements OnClickListener{
int MAX_Q = 6;
List<Question> quesList;
int score=0;
int lives=3;
int qid=0;
Question currentQ;
TextView txtQuestion, TextViewTime;
Button ansA, ansB, ansC;
private MediaPlayer mpCorrect;
private MediaPlayer mpWrong;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
DbHelper db=new DbHelper(this);
quesList=db.getAllQuestions();
currentQ=quesList.get(qid);
txtQuestion=(TextView)findViewById(R.id.questionTextView);
ansA = (Button)findViewById(R.id.ans1);
ansB=(Button)findViewById(R.id.ans2);
ansC=(Button)findViewById(R.id.ans3);
ansA.setOnClickListener(onClickListener);
ansB.setOnClickListener(onClickListener);
ansC.setOnClickListener(onClickListener);
mpCorrect = MediaPlayer.create(this, R.raw.correct);
mpWrong = MediaPlayer.create(this, R.raw.wrong);
setQuestionView();
}
public class CounterClass extends CountDownTimer{
public CounterClass(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
@Override
public void onTick(long millisUntilFinished) {
long millis = millisUntilFinished;
String secs = String.format("00:%02d", TimeUnit.MILLISECONDS.toSeconds(millis));
TextViewTime.setText(secs);
}
@Override
public void onFinish() {
wrongAnswer();
}
}
private OnClickListener onClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
switch(v.getId()){
case R.id.ans1:
if(currentQ.getANSWER().equals(ansA.getText()))
correctAnswer();
else
wrongAnswer();
break;
case R.id.ans2:
if(currentQ.getANSWER().equals(ansB.getText()))
correctAnswer();
else
wrongAnswer();
break;
case R.id.ans3:
if(currentQ.getANSWER().equals(ansC.getText()))
correctAnswer();
else
wrongAnswer();
break;
}
}
};
private void setQuestionView()
{
txtQuestion.setText(currentQ.getQUESTION());
ansA.setText(currentQ.getOPTA());
ansB.setText(currentQ.getOPTB());
ansC.setText(currentQ.getOPTC());
qid++;
showLives();
showScore();
TextViewTime=(TextView)findViewById(R.id.TextViewTime);
TextViewTime.setText("00:10");
final CounterClass timer = new CounterClass(10000, 1000);
timer.start();
}
private void showLives()
{
TextView c=(TextView)findViewById(R.id.lives);
c.setText(String.valueOf(lives));
}
private void showScore()
{
TextView d=(TextView)findViewById(R.id.score);
d.setText(String.valueOf(score));
}
private void gameOver() {
Intent intent = new Intent(QuizActivity.this, ResultActivity.class);
Bundle b = new Bundle();
b.putInt("score", score);
intent.putExtras(b);
Bundle c = new Bundle();
intent.putExtras(c);
startActivity(intent);
finish();
}
private void correctAnswer() {
score+=10;
Log.d("score", "Your score"+score); // log gia to score
mpCorrect.start();
checkGame();
}
private void wrongAnswer() {
--lives;
Log.d("lives", "Your lives"+lives);
score-=2;
Log.d("score", "Your score"+score);
if (score<0)
score=0;
mpWrong.start();
checkGame();
}
private void checkGame(){
if(qid<MAX_Q && lives>0){
currentQ=quesList.get(qid);
setQuestionView();
}
else
gameOver();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
您的 QuizActivity 不需要实现 OnClickListener + OnClick,因为您的自定义 OnClickListener 已经实现了这一部分。
针对您的实际问题:
首先,声明您的 CounterClass 变量 class-wide。
目前,每次调用 setQuestionView
时都会创建一个名为 timer
的新变量,并在每次方法完成时销毁引用(而不是对象本身),因为它是一个自动变量,仅在创建它的方法时有效。
其次,使用您现在可用的 timer
参考,重置计时器。
在自定义 OnClickListener 的 OnClick 中,在检查答案之前,使用 timer.cancel();
停止计时器。
在你的setQuestionView
中,最后不仅启动了定时器,而且还做了一个新的,所以你得到了一个完整的10秒的新定时器,旧的可能会得到GC' d(如果它没有被 cancel()
销毁的话;我这里没有 IDE,所以我无法进行代码抓取)。
你的新 setQuestionView():
private void setQuestionView()
{
txtQuestion.setText(currentQ.getQUESTION());
ansA.setText(currentQ.getOPTA());
ansB.setText(currentQ.getOPTB());
ansC.setText(currentQ.getOPTC());
qid++;
showLives();
showScore();
TextViewTime=(TextView)findViewById(R.id.TextViewTime);
TextViewTime.setText("00:10");
timer = new CounterClass(10000, 1000);
timer.start();
}
下面是一个示例,可以帮助您了解 cancel() 的工作原理。
public class TestTimer extends Activity
{
private final int START_TIME = 10000;
TextView TextViewTime;
CounterClass timer = null;
long millis = START_TIME;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
TextViewTime = (TextView) findViewById(R.id.textViewTime);
setTime();
Button buttonStart = (Button) findViewById(R.id.buttonStart);
Button buttonStop = (Button) findViewById(R.id.buttonStop);
Button buttonReset = (Button) findViewById(R.id.buttonReset);
buttonStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
timer = new CounterClass(millis, 1000);
timer.start();
}
});
buttonStop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
timer.cancel();
}
});
buttonReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
millis = START_TIME;
setTime();
}
});
}
public class CounterClass extends CountDownTimer {
public CounterClass(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
millis = millisUntilFinished;
setTime();
}
@Override
public void onFinish() {
setTime();
}
}
public void setTime() {
String secs = String.format("00:%02d", TimeUnit.MILLISECONDS.toSeconds(millis));
TextViewTime.setText(secs);
}
}
以及琐碎的布局:
<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" >
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
<Button
android:id="@+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start" />
<Button
android:id="@+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stop" />
<Button
android:id="@+id/buttonReset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="reset" />
</LinearLayout>
我正在尝试做一个简单的练习测验。我在添加倒数计时器时遇到问题。如果没有问题被回答,它工作正常,但当我回答问题时(即使它是正确的或错误的),计时器不会重置。我在 developer.android.com 上看到有 cancel() 方法,但我无法使它工作。有帮助吗?
这是我的代码。 (欢迎任何关于更好代码的建议,但我尽量保持简单,因为我是 android 开发的新手)。
public class QuizActivity extends Activity implements OnClickListener{
int MAX_Q = 6;
List<Question> quesList;
int score=0;
int lives=3;
int qid=0;
Question currentQ;
TextView txtQuestion, TextViewTime;
Button ansA, ansB, ansC;
private MediaPlayer mpCorrect;
private MediaPlayer mpWrong;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
DbHelper db=new DbHelper(this);
quesList=db.getAllQuestions();
currentQ=quesList.get(qid);
txtQuestion=(TextView)findViewById(R.id.questionTextView);
ansA = (Button)findViewById(R.id.ans1);
ansB=(Button)findViewById(R.id.ans2);
ansC=(Button)findViewById(R.id.ans3);
ansA.setOnClickListener(onClickListener);
ansB.setOnClickListener(onClickListener);
ansC.setOnClickListener(onClickListener);
mpCorrect = MediaPlayer.create(this, R.raw.correct);
mpWrong = MediaPlayer.create(this, R.raw.wrong);
setQuestionView();
}
public class CounterClass extends CountDownTimer{
public CounterClass(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
@Override
public void onTick(long millisUntilFinished) {
long millis = millisUntilFinished;
String secs = String.format("00:%02d", TimeUnit.MILLISECONDS.toSeconds(millis));
TextViewTime.setText(secs);
}
@Override
public void onFinish() {
wrongAnswer();
}
}
private OnClickListener onClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
switch(v.getId()){
case R.id.ans1:
if(currentQ.getANSWER().equals(ansA.getText()))
correctAnswer();
else
wrongAnswer();
break;
case R.id.ans2:
if(currentQ.getANSWER().equals(ansB.getText()))
correctAnswer();
else
wrongAnswer();
break;
case R.id.ans3:
if(currentQ.getANSWER().equals(ansC.getText()))
correctAnswer();
else
wrongAnswer();
break;
}
}
};
private void setQuestionView()
{
txtQuestion.setText(currentQ.getQUESTION());
ansA.setText(currentQ.getOPTA());
ansB.setText(currentQ.getOPTB());
ansC.setText(currentQ.getOPTC());
qid++;
showLives();
showScore();
TextViewTime=(TextView)findViewById(R.id.TextViewTime);
TextViewTime.setText("00:10");
final CounterClass timer = new CounterClass(10000, 1000);
timer.start();
}
private void showLives()
{
TextView c=(TextView)findViewById(R.id.lives);
c.setText(String.valueOf(lives));
}
private void showScore()
{
TextView d=(TextView)findViewById(R.id.score);
d.setText(String.valueOf(score));
}
private void gameOver() {
Intent intent = new Intent(QuizActivity.this, ResultActivity.class);
Bundle b = new Bundle();
b.putInt("score", score);
intent.putExtras(b);
Bundle c = new Bundle();
intent.putExtras(c);
startActivity(intent);
finish();
}
private void correctAnswer() {
score+=10;
Log.d("score", "Your score"+score); // log gia to score
mpCorrect.start();
checkGame();
}
private void wrongAnswer() {
--lives;
Log.d("lives", "Your lives"+lives);
score-=2;
Log.d("score", "Your score"+score);
if (score<0)
score=0;
mpWrong.start();
checkGame();
}
private void checkGame(){
if(qid<MAX_Q && lives>0){
currentQ=quesList.get(qid);
setQuestionView();
}
else
gameOver();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
您的 QuizActivity 不需要实现 OnClickListener + OnClick,因为您的自定义 OnClickListener 已经实现了这一部分。
针对您的实际问题:
首先,声明您的 CounterClass 变量 class-wide。
目前,每次调用 setQuestionView
时都会创建一个名为 timer
的新变量,并在每次方法完成时销毁引用(而不是对象本身),因为它是一个自动变量,仅在创建它的方法时有效。
其次,使用您现在可用的 timer
参考,重置计时器。
在自定义 OnClickListener 的 OnClick 中,在检查答案之前,使用 timer.cancel();
停止计时器。
在你的setQuestionView
中,最后不仅启动了定时器,而且还做了一个新的,所以你得到了一个完整的10秒的新定时器,旧的可能会得到GC' d(如果它没有被 cancel()
销毁的话;我这里没有 IDE,所以我无法进行代码抓取)。
你的新 setQuestionView():
private void setQuestionView()
{
txtQuestion.setText(currentQ.getQUESTION());
ansA.setText(currentQ.getOPTA());
ansB.setText(currentQ.getOPTB());
ansC.setText(currentQ.getOPTC());
qid++;
showLives();
showScore();
TextViewTime=(TextView)findViewById(R.id.TextViewTime);
TextViewTime.setText("00:10");
timer = new CounterClass(10000, 1000);
timer.start();
}
下面是一个示例,可以帮助您了解 cancel() 的工作原理。
public class TestTimer extends Activity
{
private final int START_TIME = 10000;
TextView TextViewTime;
CounterClass timer = null;
long millis = START_TIME;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
TextViewTime = (TextView) findViewById(R.id.textViewTime);
setTime();
Button buttonStart = (Button) findViewById(R.id.buttonStart);
Button buttonStop = (Button) findViewById(R.id.buttonStop);
Button buttonReset = (Button) findViewById(R.id.buttonReset);
buttonStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
timer = new CounterClass(millis, 1000);
timer.start();
}
});
buttonStop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
timer.cancel();
}
});
buttonReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
millis = START_TIME;
setTime();
}
});
}
public class CounterClass extends CountDownTimer {
public CounterClass(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
millis = millisUntilFinished;
setTime();
}
@Override
public void onFinish() {
setTime();
}
}
public void setTime() {
String secs = String.format("00:%02d", TimeUnit.MILLISECONDS.toSeconds(millis));
TextViewTime.setText(secs);
}
}
以及琐碎的布局:
<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" >
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
<Button
android:id="@+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start" />
<Button
android:id="@+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stop" />
<Button
android:id="@+id/buttonReset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="reset" />
</LinearLayout>