使用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
代码,但我建议您了解这两种方法以及它们的区别。