在我的多项选择测验应用程序中,必须在CountDownTimer达到0之前选择并提交答案。如果计时器达到0或提交的答案不正确,则会显示一个对话框。
这是我的问题:如果用户在未选择答案的情况下按下“提交”按钮,计时器将重置,并且文本视图会在重置时间和正确时间之间快速交替。例如,如果计时器设置为20秒,并且当计时器显示17秒时单击“提交”,则计时器显示以下内容:20、19、18、17、19 / 16、18 / 15、17 / 14和以此类推。 每次单击“提交”按钮时,这个问题就变得更加复杂。
如果在未选择答案的情况下单击“提交”,如何允许计时器继续运行?
计时器声明
type Config<T> = {
context: T;
};
type Hooks<T> = {
hooks: T;
};
type FunctionWithThis<T> = (this: T, ...args: any[]) => any;
type RemoveThis<T extends Record<string, FunctionWithThis<any>>> = {
[P in keyof T]: T[P] extends (...a: infer A) => infer R ? (...a:A) => R: never
}
const configure = <TContext extends Object,
THooks extends Record<string, FunctionWithThis<TContext>>>
(config: Config<TContext> & Hooks<THooks>) => {
const result = {
get data() { return config.context; }
};
Object.entries(config.hooks).forEach((action) => {
(result as any)[action[0]] = (...args: any[]) => action[1].call(config.context, ...args);
});
return result as { data: TContext; } & RemoveThis<THooks>;
};
const engine = configure({
context: {
foo: 12
},
hooks: {
log() {
console.log(this.foo); // this.foo is typed correctly here
}
}
});
const data = engine.data;
engine.log(); // ok
设置问题
private lateinit var timer: CountDownTimer
var isRunning: Boolean = true
计时器
private fun setQuestion() {
val question = mQuestionsList!![mCurrentPosition - 1]
defaultOptionsView()
if(mCurrentPosition == mQuestionsList!!.size + 1){
timer.cancel()
btn_submit.text = "FINISH"
}else{
btn_submit.text = "SUBMIT"
}
OnClick
timer = object: CountDownTimer(20000, 1000){
override fun onTick(millisUntilFinished: Long) {
val timeResult =
"${(millisUntilFinished/1000 / 60).toString().padStart(1, '0')}:" +
"${(millisUntilFinished/1000 % 60).toString().padStart(2, '0')}"
tv_timer.text = "$timeResult"
}
override fun onFinish() {
isRunning = false
btn_submit.callOnClick()
timer.cancel()
//cancel the timer and simulate button click to treat answer as incorrect and show dialogBox
}
}.start()
答案 0 :(得分:0)
我看不到为什么您使用已发布的代码会得到特定的行为-它的行为就像您再次运行计时器设置代码,因此一次运行了两个,这就是为什么让他们为应该显示什么时间而战。猜测一下,您没有在做timer = blabla
之前取消了旧版本,因此它只是在后台运行,因此您不再有对其的引用。
老实说,如果您是我,我会将该逻辑分解为一些单独的功能,因此您拥有应用程序需要执行的步骤,从显示问题到验证用户的答案,再到下一步。因此,您的onClick
最终会遇到这样的情况:
fun reset() {
clearTimer()
clearRadioButtons()
answerSelected = -1
}
override fun onClick(v: View?) {
when(v?.id){
R.id.radio_button1 -> answerSelected = 1
R.id.radio_button2 -> answerSelected = 2
R.id.radio_button3 -> answerSelected = 3
R.id.radio_button4 -> answerSelected = 4
R.id.btn_submit -> if (answerSelected == -1) showWarning() else submitAnswer(answerSelected)
}
}
fun showWarning() {
// show a warning toast, no need to do anything else
// (including messing with the timer)
}
fun submitAnswer(answerNumber: Int) {
// validate the input (e.g. answer between 1 and 4)
// you might want to call showWarning() here instead, in response to validation failure
recordAnswer()
reset()
// if you make setQuestion return false when there are no questions
// left, you can check that and take action
if (!setNextQuestion()) showResults()
}
有很多方法可以做到,但希望您能想到。通过将其分解为较小的任务(使用好名字,使其读起来像简单的指令),可以更轻松地推断正在发生的事情,并一步一步地采取必要的行动。
通过将诸如clearTimer()
之类的重要动作放入自己的函数中,您可以在任何地方看到该动作(通过调用该函数),并且更容易判断基本流程是否正确
答案 1 :(得分:0)
此问题与下面的setQuestion()
语句中的when
中调用计时器有关。
when {
mCurrentPosition <= mQuestionsList!!.size -> {
setQuestion()
}
通过将计时器放在onCreate
中并在timer.start()
语句中调用when
来复制该问题。删除timer.start()
可解决此问题。新的代码可以在下面找到。
onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_questions_assessment)
mQuestionsList = ConstantsAssessment.getQuestions2()
setQuestion()
btn_submit.setOnClickListener(this)
btn_back.setOnClickListener() {
startActivity(Intent(this, MainActivity::class.java))
}
timer = object: CountDownTimer(20000, 1000) {
override fun onTick(millisUntilFinished: Long) {
val timeResult =
"${(millisUntilFinished/1000 / 60).toString().padStart(1, '0')}:" +
"${(millisUntilFinished/1000 % 60).toString().padStart(2, '0')}"
tv_timer.text = "$timeResult"
}
override fun onFinish() {
isRunning = false
btn_submit.callOnClick()
timer.cancel()
}
}.start()
}
提交按钮
R.id.btn_submit -> {
if (mSelectedOptionPosition == 0 && isRunning) {
if (radio_group.checkedRadioButtonId == -1 && btn_submit.text == "SUBMIT") {
Toast.makeText(applicationContext, "Please select an answer", Toast.LENGTH_SHORT).show();
} else {
radio_group.clearCheck()
mCurrentPosition++
timer.start()
}
when {
mCurrentPosition <= mQuestionsList!!.size -> {
setQuestion()
}
else -> {
val intent = Intent(this, ResultsActivity::class.java)
intent.putExtra(ConstantsAssessment.TOTAL_CORRECT, mCorrectAnswers)
intent.putExtra(ConstantsAssessment.TOTAL_OPP, mQuestionsList!!.size)
startActivity(intent)
}
}
}