嘿,我试图在Android(Kotlin)中编写一个简单的测验,当我尝试使用它时,数组似乎为空。我从Firebase数据库获取数据,并且将其记录在LogCat中,但是当我尝试获取数组的大小时,它显示为0。
关于应该怎么做的任何指导?
这是我的代码:
import android.app.ProgressDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.google.firebase.database.*
import kotlinx.android.synthetic.main.activity_quiz.*
class QuizActivity : AppCompatActivity() {
var quizArray: ArrayList<QuizItem> = ArrayList()
private var database: FirebaseDatabase? = null
private var databaseReference: DatabaseReference? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quiz)
database = FirebaseDatabase.getInstance()
databaseReference = database!!.getReference("quiz")
var dbRef = databaseReference!!.child("mod1")
val progress = ProgressDialog(this)
progress.setMessage("Loading")
progress.isIndeterminate
var valueEventListener: ValueEventListener = object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
var contentSnapshot: DataSnapshot = p0
var contentChildren: Iterable<DataSnapshot> = contentSnapshot.children
for (content: DataSnapshot in contentChildren){
var quizItem: QuizItem = content.getValue(QuizItem::class.java)!!
Log.d("\n Received Data", "data: statement = "+quizItem.statement
+" id = "+quizItem.id
+" correctOption = "+quizItem.correctOption
+" optionA"+quizItem.optionA
+" optionB"+quizItem.optionB
+" optionC"+quizItem.optionC
+" optionD"+quizItem.optionD
+" \n ")
quizArray.add(quizItem)
Toast.makeText(applicationContext, "Item added for ID = "+quizItem.id, Toast.LENGTH_SHORT).show()
}
print(quizArray)
progress.dismiss()
Log.d("Data Received", "this@QuizActivity")
Log.d("Progress Bar", "this@QuizActivity Progress Bar Dismissed")
}
}
dbRef!!.addValueEventListener(valueEventListener)
progress.show()
Log.d("Progress Bar", "this@QuizActivity Progress Bar Sent")
Toast.makeText(applicationContext, "Array Size = "+quizArray.size, Toast.LENGTH_SHORT).show()
startQuiz()
}
private fun startQuiz(){
var total: Int = quizArray.size
Toast.makeText(applicationContext, total.toString(), Toast.LENGTH_SHORT).show()
var correct: Int = 0
var incorrect: Int = 0
var done: Int = 0
tv_quiz_total.text = total.toString()
tv_quiz_correct.text = correct.toString()
tv_quiz_incorrect.text = incorrect.toString()
tv_quiz_done.text = done.toString()
var i = 0
while (i<total){
tv_quiz_statement.text = quizArray[i].statement
tv_quiz_opA.text = quizArray[i].optionA
tv_quiz_opB.text = quizArray[i].optionB
tv_quiz_opC.text = quizArray[i].optionC
tv_quiz_opD.text = quizArray[i].optionD
tv_quiz_opA.setOnClickListener {
if (quizArray[i].correctOption == 1){
correct++
done++
tv_quiz_correct.text = correct.toString()
tv_quiz_done.text = done.toString()
i++
} else {
incorrect++
done++
i++
tv_quiz_incorrect.text = incorrect.toString()
}
}
tv_quiz_opB.setOnClickListener {
if (quizArray[i].correctOption == 2){
correct++
done++
tv_quiz_correct.text = correct.toString()
tv_quiz_done.text = done.toString()
i++
} else {
incorrect++
done++
i++
tv_quiz_incorrect.text = incorrect.toString()
}
}
tv_quiz_opC.setOnClickListener {
if (quizArray[i].correctOption == 3){
correct++
done++
tv_quiz_correct.text = correct.toString()
tv_quiz_done.text = done.toString()
i++
} else {
incorrect++
done++
i++
tv_quiz_incorrect.text = incorrect.toString()
}
}
tv_quiz_opD.setOnClickListener {
if (quizArray[i].correctOption == 4){
correct++
done++
tv_quiz_correct.text = correct.toString()
tv_quiz_done.text = done.toString()
i++
} else {
incorrect++
done++
i++
tv_quiz_incorrect.text = incorrect.toString()
}
}
}
}
}
谢谢
答案 0 :(得分:1)
Firebase API为asynchronous
,这意味着onDataChange()
函数在被调用后立即返回,而从其返回的Task
的回调将在一段时间后被调用。无法保证需要多长时间。因此,可能需要几百毫秒到几秒钟的时间才能获得该数据。由于该方法会立即返回,因此您尝试在此方法之外使用的quizArray
ArrayList始终为空,因为数据尚未完成加载。
基本上,您正在尝试从异步的API同步使用值。那不是一个好主意。您应该按预期异步处理API。
此问题的快速解决方案是在回调内使用ArrayList only 的值。如果您想在外部使用它,建议您从此 post 中查看anwser的最后一部分,其中已经解释了如何使用自定义回调来完成它。
答案 1 :(得分:0)
正如Alex Mamo指出的那样,您试图同步访问数组,而填充数组的函数是异步的。
尝试在onDataChange()方法内调用startQuiz()函数。像这样:
var valueEventListener: ValueEventListener = object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
var contentSnapshot: DataSnapshot = p0
var contentChildren: Iterable<DataSnapshot> = contentSnapshot.children
for (content: DataSnapshot in contentChildren){
var quizItem: QuizItem = content.getValue(QuizItem::class.java)!!
Log.d("\n Received Data", "data: statement = "+quizItem.statement
+" id = "+quizItem.id
+" correctOption = "+quizItem.correctOption
+" optionA"+quizItem.optionA
+" optionB"+quizItem.optionB
+" optionC"+quizItem.optionC
+" optionD"+quizItem.optionD
+" \n ")
quizArray.add(quizItem)
Toast.makeText(applicationContext, "Item added for ID = "+quizItem.id, Toast.LENGTH_SHORT).show()
}
print(quizArray)
progress.dismiss()
// call the startQuiz function here
startQuiz()
Log.d("Data Received", "this@QuizActivity")
Log.d("Progress Bar", "this@QuizActivity Progress Bar Dismissed")
}
}