英文:
How can I update my UI after a coroutine is completed in Kotlin for Android?
问题
我使用Retrofit和协程从API获取语言列表。我的ViewModel在创建时加载语言列表。我想将此列表加载到一个下拉框中,但每当我更新下拉框的数据时,ViewModel中的数据还没有完全加载。
以下是我的ViewModel类,用于从API加载数据:
class TranslateViewModel : ViewModel() {
var langToCode = HashMap<String, String>()
var codeToLang = HashMap<String, String>()
private val translateRepository = TranslateRepository()
init {
viewModelScope.launch {
val langList = try {
translateRepository.getLangList()
} catch (e: IOException) {
Log.e(TAG, "IOException", e)
return@launch
} catch (e: HttpException) {
Log.e(TAG, "HTTPException", e)
return@launch
}
if (langList.isSuccessful && langList.body() != null) {
codeToLang = langList.body()!!.langList
langToCode = codeToLang.map { (key, value) ->
value to key
}.toMap() as HashMap<String, String>
} else {
Log.d(TAG, "Get lang list failure")
}
}
}
}
我想将语言列表加载到下拉框中,但是我的ViewModel加载数据的速度太慢了,所以langList
变量始终为空。
以下是如何在协程完成加载数据后立即更新UI的方法:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.apply {
sourceLanguage.apply {
viewModel.viewModelScope.launch {
val langList = viewModel.langToCode.keys.toList()
val arrayAdapter = ArrayAdapter(
context,
android.R.layout.simple_spinner_item,
langList
).also {
it.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}
adapter = arrayAdapter
}
}
}
}
感谢您的帮助,请原谅我英语不太好的问题。
英文:
I use Retrofit and Coroutines to fetch a list of languages from an API. My ViewModel loads the list of languages whenever it is created. I want to load this list into a spinner, but whenever I update the spinner data, the data in the ViewModel hasn't completely loaded.
Here my viewmodel class to load data from an api
class TranslateViewModel : ViewModel() {
var langToCode = HashMap<String, String>()
var codeToLang = HashMap<String, String>()
private val translateRepository = TranslateRepository()
init {
viewModelScope.launch {
val langList = try {
translateRepository.getLangList()
} catch (e: IOException) {
Log.e(TAG, "IOException", e)
return@launch
} catch (e: HttpException) {
Log.e(TAG, "HTTPException", e)
return@launch
}
if (langList.isSuccessful && langList.body() != null) {
codeToLang = langList.body()!!.langList
langToCode = codeToLang.map { (key, value) ->
value to key
}.toMap() as HashMap<String, String>
} else {
Log.d(TAG, "Get lang list failure")
}
}
}
}
I want to load my list of languages into my spinner but my viewmodel is taking too long to load the data, so the langList variable is alway empty.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewBinding.apply {
sourceLanguage.apply {
val langList = viewModel.langToCode.keys.toList()
val arrayAdapter = ArrayAdapter (
context,
android.R.layout.simple_spinner_item,
langList
).also { it.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
}
this.adapter = arrayAdapter
}
}
I want to know how to update my UI immediately after my coroutine has finished loading data. I appreciate all of your help, and please forgive me for my poor English skills.
答案1
得分: 0
在您的情况下,更新您的ViewModel如下所示-
class TranslateViewModel : ViewModel() {
private val _langList = MutableLiveData<List<String>>()
val langList: LiveData<List<String>> get() = _langList
init {
viewModelScope.launch {
if (langList.isSuccessful && langList.body() != null) {
codeToLang = langList.body()!!.langList
langToCode = codeToLang.map { (key, value) ->
value to key
}.toMap() as HashMap<String, String>
_langList.value = langToCode.keys.toList() // 更新LiveData的值
} else {
Log.d(TAG, "获取语言列表失败")
}
}
}
}
在您的UI代码中,观察LiveData并按如下方式更新Spinner-
viewModel.langList.observe(viewLifecycleOwner, { langList ->
val arrayAdapter = ArrayAdapter(
context,
android.R.layout.simple_spinner_item,
langList
).also { it.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
}
sourceLanguage.adapter = arrayAdapter
})
点击此链接获取更多详细信息- https://developer.android.com/topic/libraries/architecture/livedata
英文:
In Your case update your viewmodel as below-
class TranslateViewModel : ViewModel() {
private val _langList = MutableLiveData<List<String>>()
val langList: LiveData<List<String>> get() = _langList
init {
viewModelScope.launch {
if (langList.isSuccessful && langList.body() != null) {
codeToLang = langList.body()!!.langList
langToCode = codeToLang.map { (key, value) ->
value to key
}.toMap() as HashMap<String, String>
_langList.value = langToCode.keys.toList() // Update the LiveData value
} else {
Log.d(TAG, "Get lang list failure")
}
}
}
}
In your UI code to observe the LiveData and update the spinner as below-
viewModel.langList.observe(viewLifecycleOwner, { langList ->
val arrayAdapter = ArrayAdapter(
context,
android.R.layout.simple_spinner_item,
langList
).also { it.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
}
sourceLanguage.adapter = arrayAdapter
})
Follow this link for more detail - https://developer.android.com/topic/libraries/architecture/livedata
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论