Reputation: 27
Im working on a quizgame and i want to store some ids in a MutableLiveData-arraylist. Therfore i made a function to loop all my documents in de database and add each ID to the arraylist. BUT the outcome is always null. I don't see where i go wrong?
I'm working with a MVVM-structure
GameViewModel:
class GameViewModel : ViewModel() {
// database instance
val db = FirebaseFirestore.getInstance()
// the current category
private val _category = MutableLiveData<String>()
val category: LiveData<String>
get() = _category
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>()
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
// the current question
private val _question = MutableLiveData<String>()
val question: LiveData<String>
get() = _question
/**
* Set Current Category
*/
fun SetCategory (categoryName: String){
_category.value = categoryName
}
/**
* Get the list of QuestionIds
*/
fun GetListQuestionIds() {
db.collection("questions")
.whereEqualTo("category", "$_category")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
_questionIdsArray.value?.add(document.data["questionid"] as Long)
Log.d("GetSize","${_questionIdsArray.value?.size}")
}
Log.d("GetSize2","${_questionIdsArray.value?.size}")
}
.addOnFailureListener { exception ->
Log.w("errorforloop", "Error getting documents: ", exception)
}
}
/**
* Get a Question
*/
fun GetQuizQuestion() {
Log.d("retro","${_questionIdsArray.value?.size}")
db.collection("questions")
.whereEqualTo("category", "$_category")
.whereEqualTo("questionid", "${_questionIdsArray.value?.get(0)}")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
_question.value = document.data["question"].toString()
}
}
.addOnFailureListener { exception ->
Log.w("err", "Error getting documents: ", exception)
}
}
GAMEFRAGMENT:
class GameFragment : Fragment() {
private lateinit var viewModel: GameViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentGameBinding.inflate(inflater)
// Get the viewModel
viewModel = ViewModelProvider(this).get(GameViewModel::class.java)
binding.lifecycleOwner = this
// Set the viewModel for DataBinding - this allows the bound layout access to all of the data in the VieWModel
binding.gameviewModel = viewModel
//arguments passed
val selectedCategory = arguments?.getString("selectedCategory")!!
//set current category so that the viewModel can use it
viewModel.SetCategory(selectedCategory)
viewModel.GetListQuestionIds()
viewModel.GetQuizQuestion()
return binding.root
}
If someone can enlighten me ...
Upvotes: 1
Views: 727
Reputation: 10155
Your Problem
You're not initializing the array. This is your code:
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>()
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
This declares a MutableLiveData
of type ArrayList<Long>
, but does not initialize it so its value
defaults to null
.
In your for loop you conditionally add items:
_questionIdsArray.value?.add(document.data["questionid"] as Long)
But of course value
was never initialized so it's null so add
is no-op (does nothing).
The Solution
Just ensure you initialize the live data object at some point.
You could do this inline in the declaration:
// the list of questionIds of the selected category
private val _questionIdsArray = MutableLiveData<ArrayList<Long>>(arrayListOf())
val questionIdsArray: LiveData<ArrayList<Long>>
get() = _questionIdsArray
Or during your attempt to populate the list:
.addOnSuccessListener { documents ->
val idsArray = arrayListOf<Long>() // Non-null list to add to
for (document in documents) {
idsArray.add(document.data["questionid"] as Long)
Log.d("GetSize","${idsArray.size}")
}
_questionIdsArray.value = idsArray // Now set live data with a valid list
Log.d("GetSize2","${_questionIdsArray.value?.size}")
}
Upvotes: 5