问题
I have following project in Github : https://github.com/Ali-Rezaei/TVMaze
I have started to using Koin as dependency injection framework in a sample app :
class TVMazeApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@TVMazeApplication)
modules(networkModule)
modules(persistenceModule)
modules(repositoryModule)
modules(viewModelModule)
}
}
}
This is my repository class :
class ShowRepository(
private val dao: ShowDao,
private val api: TVMazeService,
private val context: Context
) {
/**
* A list of shows that can be shown on the screen.
*/
val shows = resultLiveData(
databaseQuery = {
Transformations.map(dao.getShows()) {
it.asDomainModel()
}
},
networkCall = { refreshShows() })
/**
* Refresh the shows stored in the offline cache.
*/
private suspend fun refreshShows(): Result<List<Show>> =
try {
if (isNetworkAvailable(context)) {
val shows = api.fetchShowList().await()
dao.insertAll(*shows.asDatabaseModel())
Result.success(shows)
} else {
Result.error(context.getString(R.string.failed_internet_msg))
}
} catch (err: HttpException) {
Result.error(context.getString(R.string.failed_loading_msg))
}
}
And my ViewModel :
class MainViewModel(
repository: ShowRepository
) : ViewModel() {
private val _shows = repository.shows
val shows: LiveData<Result<List<Show>>>
get() = _shows
}
And I observe LiveData in my Activity :
viewModel.shows.observe(this, Observer { result ->
when (result.status) {
Result.Status.SUCCESS -> {
binding.loadingSpinner.hide()
viewModelAdapter.submitList(result.data)
}
Result.Status.LOADING -> binding.loadingSpinner.show()
Result.Status.ERROR -> {
binding.loadingSpinner.hide()
Snackbar.make(binding.root, result.message!!, Snackbar.LENGTH_LONG).show()
}
}
})
When I click on Back button, Activity get destroyed ( but instance of app still exist as I can access it from recent apps). What I expect is a call to refreshShows() method when I start the app again, but it never get called.
But when I destroy instance of app by clearing from recent app and start the app, refreshShows() get called.
What should I do to have a call on refreshShows() every time onCreate()
callback of Activity get called?
fun <T, A> resultLiveData(databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Result<A>): LiveData<Result<T>> =
liveData(Dispatchers.IO) {
emit(Result.loading<T>())
val source = databaseQuery.invoke().map { Result.success(it) }
emitSource(source)
val result = networkCall.invoke()
if (result.status == Result.Status.ERROR) {
emit(Result.error<T>(result.message!!))
emitSource(source)
}
}
回答1:
Your refreshShows() in your repository is only get called when a new network request is done. The idea of your livedata is to provide the latest result when its fragment/activity is recreated, so when your screen rotates or you resume an activity it doesnt triggers another request as the livedata already have the latest result and you dont have a stateful connection with your network database/server (if you were observing data from Room it would receive the latest change if any).
The simpliest way I find to "fix" this, is to actually have your viewmodel val shows to be a fun, like this:
class MainViewModel(
repository: ShowRepository
) : ViewModel() {
private val _shows = repository.shows()
val shows: LiveData<Result<List<Show>>>
get() = _shows
}
However using like this, everytime the screen rotates a new network call will be made thus calling your refreshShows()
来源:https://stackoverflow.com/questions/62092123/refreshshows-in-repository-get-called-every-time-oncreate-callback-of-activi