Размер ArrayList равен нулю - PullRequest
0 голосов
/ 06 ноября 2018

Эй, я пытался написать простую викторину в 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()
            }
        }

    }

}

}

Спасибо

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Как указал Алекс Мамо, вы пытаетесь получить доступ к массиву синхронно, в то время как функция, которая заполняет массив, является асинхронной.

Попробуйте вызвать функцию startQuiz () внутри метода onDataChange (). Примерно так:

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")

    }

}
0 голосов
/ 06 ноября 2018

API Firebase имеют значение asynchronous, что означает, что функция onDataChange() возвращается сразу после ее вызова, а обратный вызов из Task, который она возвращает, будет вызван через некоторое время. Там нет никаких гарантий о том, сколько времени это займет. Таким образом, получение этих данных может занять от нескольких сотен миллисекунд до нескольких секунд. Поскольку этот метод немедленно возвращается, ваш quizArray ArrayList, который вы пытаетесь использовать вне этого метода, всегда будет пустым, поскольку данные еще не закончили загрузку.

По сути, вы пытаетесь использовать значение синхронно из асинхронного API. Это не очень хорошая идея. Вы должны обрабатывать API-интерфейсы асинхронно, как и предполагалось.

Быстрое решение этой проблемы - использование значения ArrayList only внутри обратного вызова. Если вы хотите использовать его снаружи, я рекомендую вам посмотреть последнюю часть моего ответа из этого поста , в котором я объяснил, как это можно сделать с помощью пользовательского обратного вызова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...