I want to show a list of Strings in a MaterialAlertDialog. I'm loading them from Room Db within a suspended function and use a callback to set the items in the DialogFragment. Here the code:
PlayerDao.kt
@Dao
interface PlayerDao {
@Query("SELECT * FROM players WHERE playable = 1")
suspend fun getPlayableCharacters():List<PlayerEntity>
}
PlayerRepository.kt
@Singleton
class PlayerRepository @Inject constructor(private val db: AppDatabase) {
suspend fun getPlayableCharacters():List<Player>{
return db.playerDao().getPlayableCharacters().map {
Player.fromEntity(it)
}
}
}
WelcomeViewModel.kt
@HiltViewModel
class WelcomeViewModel @Inject constructor(private val repository: PlayerRepository) : ViewModel() {
fun loadPlayableChars(onResult: (List<Pair<String, Int>>) -> Unit) {
viewModelScope.launch {
val result: List<Pair<String, Int>> = withContext(Dispatchers.IO) {
repository.getPlayableCharacters().map {
Pair(it.name, it.getLevel())
}
}
onResult(result)
}
}
}
WelcomeFragment.kt
@AndroidEntryPoint
class WelcomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWelcomeBinding.inflate(inflater, container, false)
binding.loadCharButton.setOnClickListener {
SelectCharacterDialogFragment().show(childFragmentManager, "SelectCharacterDialogFragment")
}
return binding.root
}
}
SelectCharacterDialogFragment.kt
@AndroidEntryPoint
class SelectCharacterDialogFragment : DialogFragment() {
val viewModel: WelcomeViewModel by viewModels()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val itemsToShow = arrayOf<String>()
val items = mutableListOf<Pair<String, Int>>()
val dialogBuilder = MaterialAlertDialogBuilder(requireContext())
.setTitle("Choose a character")
viewModel.loadPlayableChars { list ->
Log.d("DIALOG", "in Callback: $list")
items += list
val itemsToShow = items.map {
"${it.first}: ${it.second}"
}.toTypedArray()
dialogBuilder.setItems(itemsToShow) { dialog, which ->
when (which) {
0 -> Log.d("Dialog", "$which")
else -> Log.d("Dialog", "$which")
}
}
}
Log.d("DIALOG", "Returning dialog")
return dialogBuilder.create()
}
}
The log output inside the callback tells me that the data is available. But to late. The method has already returned when the callback is executed:
D/DIALOG: Returning dialog
I/System.out: SQL: SELECT * FROM players WHERE playable = 1
Here is a screenshot:
What did I wrong? What is the best practice to make a one-shot request to show items inside an AlertDialog?