与LiveData观察者、适配器、协程混淆



使用MVVM架构

我很难弄清楚我应该如何完成这项任务。我的想法是,我想从REST API检索歌曲列表,将该列表传递给使用歌曲列表创建自定义回收器视图的SongListAdapter,然后扩展该视图。

在它像

那么简单之前
//Get Songs
CoroutineScope(IO).launch {
val songList = viewModel.getSongs()                  
withContext(Main){
val rvSongs = rvSongs as RecyclerView
val adapter = SongListAdapter(songList)
rvSongs.adapter = adapter
rvSongs.layoutManager = LinearLayoutManager(this@SongListActivity)
}
}

但是现在我想用liveData来做这件事,而val songList = viewModel.getSongs()没有削减它。相反,我需要使用

viewModel.getSongs().observe(this@SongListActivity, Observer {
//UI Stuff
}

问题是getSongs()命中api端点来检索列表,这需要在后台线程上完成。但是观察者不能在后台线程上被调用…这让我觉得我处理这件事的方式是错误的。

我在想我可以有两种不同的功能来获取歌曲…一个到达端点,另一个将List<Song>数据转换为MutableLiveData<List<Song>>,但感觉我过于复杂了。我应该如何使用livedata来实现这一点呢?

SongListActivity

class SongListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.song_list) //I changed this for testing, change back to activity_main
//Set View Model
val viewModel = ViewModelProvider(this).get(SongListActivityViewModel::class.java)
//Get Songs
CoroutineScope(IO).launch{
//Need to hit getSongs() endpoint here
withContext(Main){
val rvSongs = rvSongs as RecyclerView
val adapter = SongListAdapter(songList)
rvSongs.adapter = adapter
rvSongs.layoutManager = LinearLayoutManager(this@SongListActivity)
}
}
}
}

SongListActivityViewModel

class SongListActivityViewModel : ViewModel() {
private val songLiveData = MutableLiveData<List<Song>?>()
//Returns list of songs on the first page.
suspend fun getSongs(): MutableLiveData<List<Song>?> {
//Hit Endpoint
val songPage1 = FunkwhaleRepository.getSongs()
//Store as LiveData
songLiveData.postValue(songPage1.results)
return songLiveData
}
}

首先,我认为你应该考虑使用适当的Android生命周期范围来启动你的协同程序。如果你在像Activity这样的Android组件中创建了一个作用域,那么你应该考虑在活动被销毁时自己取消它。这里有一些很好的文档,我建议你看一看。

关于你的实际问题,你的思路是对的!

首先,你的ViewModel应该像在你的代码中一样暴露一些LiveData,但应该在它的init块中启动一个协程作用域,从端点获取数据。然后,当它获取它时,你应该只设置LiveData值为你加载的数据。

在你的活动中,而不是试图启动一个协程来设置你的RecyclerView,事先只设置LayoutManager,然后开始观察暴露的LiveData。然后,当观察到的数据发生变化时,才将适配器设置为RecyclerView

一个快速的伪代码概述可能会有所帮助:

ViewModel

ViewModel {
val liveData = MutableLiveData<>()
init {
scope.launch {
liveData.value = api.fetch()
}
}
}

Activity {
onCreate {
...
recyclerView.layoutManager = LinearLayoutManager
...
viewModel.liveData.observe {
recyclerView.adapter = Adapter(data)
}
}
}

注意:您也可以使用liveData(LiveDataScope<T>.() -> Unit)构建器函数来简化ViewModel代码,但我建议您了解这两种方法以及它们的区别。

相关内容

  • 没有找到相关文章

最新更新