我正在努力在 MVVM 模式上使用實時資料。該應用程式應該:
- 從 API 中獲取資料(它正確)
- 將該資料存盤在ViewModel的實時資料物件中
- 然后fragment呼叫Observer方法填充recyclerView。
問題出現在第3點,它什么也沒做,我找不到解決方案。
這是相關的代碼。(如果我遺漏了什么,我會盡快回答)
主要活動:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Custom button to fetch data from api and log the Live Data value.
binding.refreshFab.setOnClickListener {
viewModel.fetchPlayerData()
Log.d("gabs", "${viewModel.livePlayerlist.value}")
}
}
}
視圖模型:
class SharedViewModel(app: Application): AndroidViewModel(app) {
// val playerDao = LaRojaDB.getDatabase(app).playerDao()
lateinit var playerList: Players
val livePlayerlist: MutableLiveData<MutableList<Players.PlayersItem>> by lazy {
MutableLiveData<MutableList<Players.PlayersItem>>()
}
fun fetchPlayerData() {
CoroutineScope(Dispatchers.IO).launch {
val response = MyService.getLaRojaService().getAllPlayers()
withContext(Dispatchers.Main) {
if (response.isSuccessful) {
val body = response.body()
if(!body.isNullOrEmpty()){
playerList = body
val playerArrayList = mutableListOf<Players.PlayersItem>()
playerList.forEach {
playerArrayList.add(it)
}
livePlayerlist.value = playerList
}
}
}
}
}
}
顯示回收器視圖的片段:(片段已經顯示,我設定了一個 textView 作為標題,以確保因為我也是使用片段的新手。)
class PlayerListFragment : Fragment() {
private var _binding: FragmentPlayerListBinding? = null
private val binding get() = _binding!!
private val model: SharedViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentPlayerListBinding.inflate(inflater, container, false)
binding.rvPlayerList.layoutManager = LinearLayoutManager(activity)
----> // This is the observer that does not update the UI** <----
model.livePlayerlist.observe( viewLifecycleOwner, {
binding.rvPlayerList.adapter = PlayerAdapter(it)
})
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_player_list, container, false)
}
}
提前謝謝大家,希望我終于可以了解導致問題的原因!
uj5u.com熱心網友回復:
我認為您不需要切換協程背景關系。如果我正在查看此代碼,我會期望進行一些更改:
這都應該在相同的IO背景關系中。然后你postValue到你的liveData。
fun fetchPlayerData() {
viewModelScope.launch(Dispatchers.IO) {
val xx = api.fetch()
...
_playerState.postValue(xx) //see below
}
}
此外,最好不要公開可變狀態,因此您的 ViewModel 不應該公開MutableLiveData(這不應該真的是懶惰的)。但最好將狀態封裝在一個密封的類中:
//delete this
val livePlayerlist: MutableLiveData<MutableList<Players.PlayersItem>> by lazy {
MutableLiveData<MutableList<Players.PlayersItem>>()
}
應該是:(名稱只是偽代碼,我不知道這段代碼是關于什么的)
sealed class PlayerDataState {
data class ListAvailable(data: List<Players.PlayersItem>>): PlayerDataState
object Loading(): PlayerDataState
}
還有你的新 LiveData:
private val _playerState = MutableLiveData<PlayerDataState>()
val playerState: LiveData<PlayerDataState>() get() = _playerState
最后,從 UI 觀察時,您只需...
model.playerState.observe(viewLifecycleOwner, {
when (it) {
is Loading -> ...
is ListAvailable -> binding.rvPlayerList.adapter = PlayerAdapter(it.data)
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/409532.html
標籤:
