我想启动一个CoroutineScope,以便在闪屏期间开始从数据库加载数据,以便主活动可以快速显示数据,但我不想延迟闪屏以等待结果(这是一个很好的实践?)
当Main活动用ViewModel列表的观察者设置UI时,调用ViewModelloadList()
,这样它就可以获得由Repository加载的列表并发布值,这样观察者就会被触发。但是存储库工作在不同的线程上,ViewModel可以首先请求存储库填充的数据。因此,当存储库从数据库加载数据时,我需要触发ViewModel
SplashScreen的代码:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//this class load the data from database
PersistenceSingleton.getInstance(application)
startActivity(Intent(this, MainActivity::class.java))
finish()
}
PersistenceSingleton:
private var dbAccess: PersistenceSingletonRepository? = null // Singleton
private lateinit var db: PokemonDatabase
var listOfPokemon: MutableLiveData<MutableList<Pokemon>> = MutableLiveData()
fun getInstance(context: Context) = synchronized(this){
if (dbAccess == null) {
dbAccess = PersistenceSingleton()
db = PokemonDatabase.getInstance(context)
//load all pokemon
CoroutineScope(Dispatchers.IO).launch {
val lan = Locale.getDefault().language
val list = if (lan.equals("it")) {
db.pokemonDao().loadAllPokemonIt()
} else {
db.pokemonDao().loadAllPokemon()
}
CoroutineScope(Dispatchers.Main).launch {
listOfPokemon.value = list
}
}
}
dbAccess
}
ViewModel:
var pokemonList: MutableLiveData<MutableList<Pokemon>> = MutableLiveData()
fun loadLists() {
//list could be empty. ViewModel need to observe the list on PersistenceSingleton (Repository)
pokemonList.value = PersistenceSingleton.listOfPokemon.value
}
主活动setUI:
private fun setUI() {
val observer = Observer<List<Pokemon>> { list ->
if (list != null) {
//hide progress bar and set recycler view adapter
binding.pbPokemonlist.visibility = View.INVISIBLE
adapter = PokemonListAdapter(list)
binding.rvPokemon.adapter = adapter
}
}
pokemonListVM.pokemonList.observe(this, observer)
//inflate the recycler view
pokemonListVM.loadLists()
}
编辑
使ViewModel成为一个观察者,我使用MediatorLiveData
,所以我的新ViewModel:
var pokemonList: MutableLiveData<MutableList<Pokemon>> = MutableLiveData()
private val pokemonListMediator: MediatorLiveData<List<Pokemon>> = MediatorLiveData()
init {
val observer = Observer<MutableList<Pokemon>> { list ->
Log.d("POKEMON", "onChange")
pokemonList.value = list
}
pokemonListMediator.addSource(PersistenceSingletonRepository.listOfPokemon, observer)
}
//load full list of Pokemon
fun loadLists() {
//list could be empty. ViewModel need to observe the list on PersistenceSingleton (Repository)
pokemonList.value = PersistenceSingletonRepository.listOfPokemon.value
}
但是观察者onChange()
从未被调用过
您可以将Lists
置于ViewModel
中并使它们成为MutableLiveData
。
您将开始在Activity
的onCreate
函数内observe
MutableLiveData
对象。
在完成了最低限度的设置之后,在onCreate
中调用loadLists
。(就像获得RecyclerView
并设置其Adapter
,以便您的数据有地方去)
你的loadList
函数应该看起来像这样
public var pokemonList: MutableLiveData<List<Pokemon>> = MutableLiveData()
public var typeList : MutableLiveData<List<Type>> = MutableLiveData()
fun loadLists(context: Context) {
db = PokemonDatabase.getInstance(context)
//separate CoroutineScope for each database call
CoroutineScope(Dispatchers.IO).launch {
pokemonList.postValue(db.pokemonDao().loadAllPokemon())
}
CoroutineScope(Dispatchers.IO.launch{
typeList.postValue(db.pokemonDao().loadAllType())
}
}
你的OnCreate
应该有这个
mainViewModel.pokemonList.observe(this, Observer { pokemans ->
//something like this
pokemonAdapter.list = pokemans
})
mainViewModel.typeList.observe(this, Observer { types->
//something like this
typeAdapter.list = types
})
这样,你的数据应该很快就能得到,任何更复杂的东西都会伤害到你。
编辑:配合你的编辑。
差不多了,你只需要另一个回调,我将使用
androidx.lifecycle.Observer<T>
。
PersistenceSingleton.getInstance(getApplication())!!.getListOfPokemon(
Observer<List<Pokemon>> { pokemon ->{
pokemonList.postValue(pokemon)
}
)
然后在getListOfPokemon
函数
CoroutineScope(Dispatchers.IO).launch {
observer.onChanged(db.pokemonDao().loadAllPokemon())
}
当且仅当pokemon可用时,这将返回pokemon列表。你不必担心口袋妖怪的空列表,因为在有实际数据之前不会发出任何东西。