首页 > 解决方案 > 每次调用 Activity 的 onCreate() 时都会调用 Repository 中的刷新(不在屏幕旋转中)

问题描述

我在 Github 有以下项目:https ://github.com/AliRezaeiii/TVMaze

我已经开始在示例应用程序中使用 Koin 作为依赖注入框架:

class TVMazeApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin {
            androidContext(this@TVMazeApplication)
            modules(networkModule)
            modules(persistenceModule)
            modules(repositoryModule)
            modules(viewModelModule)
        }
    }
}

这是我的存储库类:

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))
        }
}

我的 ViewModel :

class MainViewModel(
    repository: ShowRepository
) : ViewModel() {

    private val _shows = repository.shows
    val shows: LiveData<Result<List<Show>>>
        get() = _shows
}

我在 Activity 中观察 LiveData :

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()
                }
            }
        })

当我单击后退按钮时,活动被破坏(但应用程序实例仍然存在,因为我可以从最近的应用程序访问它)。我期望的是当我再次启动应用程序时调用 refreshShows() 方法,但它永远不会被调用。

但是当我通过从最近的应用程序中清除并启动应用程序来销毁应用程序实例时,会调用 refreshShows()。

每次onCreate()调用 Activity 回调时,我应该怎么做才能调用 refreshShows()?

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)
        }
    }

标签: androidandroid-livedata

解决方案


只有在完成新的网络请求时才会调用存储库中的 refreshShows()。您的 livedata 的想法是在重新创建其片段/活动时提供最新结果,因此当您的屏幕旋转或恢复活动时,它不会触发另一个请求,因为 livedata 已经具有最新结果并且您没有与您的网络数据库/服务器(如果您从 Room 观察数据,它将收到最新的更改(如果有))。

我发现“解决”这个问题的最简单方法是让你的 viewmodel val 显示出来很有趣,就像这样:

class MainViewModel(
    repository: ShowRepository
) : ViewModel() {

    private val _shows = repository.shows()
    val shows: LiveData<Result<List<Show>>>
        get() = _shows
}

但是像这样使用,每次屏幕旋转时都会进行新的网络调用,从而调用您的refreshShows()


推荐阅读