LiveData observeForever 不工作
LiveData observeForever not working
我有一个 WeatherRepository class,它调用 WeatherProvider class 开始获取天气。
成功获取天气后,我只是 post 使用 postValue 函数的天气,但是 WeatherRepository class 的 init 块中实时数据的观察者永远不会被调用.
我很困惑,我错过了什么...
任何见解都将非常有帮助。
这是我的存储库和提供程序代码:
class WeatherRepository @Inject constructor(private var weatherDao: WeatherDao, private var weatherProvider: WeatherProvider) {
private fun startFetchWeatherService() {
weatherProvider.startFetchWeatherService()
}
init {
// Control flow always gets to this point
var weather = weatherProvider.getDownloadedWeather()
weather.observeForever { // This observer never gets called
if (it != null) AsyncTask.execute { insertWeather(it) }
}
if (isFetchNeeded()) {
startFetchWeatherService() // Android Studio always execute this line since no data is inserted by observer and fetch is needed
}
}
....
}
class WeatherProvider(private val context: Context) {
private val mDownloadedWeather = MutableLiveData<List<Weather>>()
...
fun getDownloadedWeather(): MutableLiveData<List<Weather>> = mDownloadedWeather
fun getFromInternet() {
...
call.enqueue(object : Callback<WorldWeatherOnline> {
override fun onFailure(call: Call<WorldWeatherOnline>?, t: Throwable?) {} // TODO show error
override fun onResponse(call: Call<WorldWeatherOnline>?, response: Response<WorldWeatherOnline>?) {
if (response != null) {
val weather = response.body()?.data
if (weather != null) {
mDownloadedWeather.postValue(WeatherUtils.extractValues(weather)) // app always gets to this point and WeatherUtils successfully returns the List of weathers full of data
}
}
}
})
}
fun startFetchWeatherService() {
val intentToFetch = Intent(context, WeatherSyncIntentService::class.java)
context.startService(intentToFetch)
}
}
...
// Dependency injection always works
// Here's my dagger2 module (other modules are very simillar to this one)
@Module
class ApplicationModule(private val weatherApplication: WeatherApplication) {
@Provides
internal fun provideWeatherApplication(): WeatherApplication {
return weatherApplication
}
@Provides
internal fun provideApplication(): Application {
return weatherApplication
}
@Provides
@Singleton
internal fun provideWeatherProvider(context: WeatherApplication): WeatherProvider {
return WeatherProvider(context)
}
}
@Singleton
class CustomViewModelFactory constructor(private val weatherRepository: WeatherRepository, private val checklistRepository: ChecklistRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
when {
modelClass.isAssignableFrom(WeatherViewModel::class.java) ->
return WeatherViewModel(weatherRepository) as T
modelClass.isAssignableFrom(ChecklistViewModel::class.java) ->
return ChecklistViewModel(checklistRepository) as T
else ->
throw IllegalArgumentException("ViewModel Not Found")
}
}
}
class WeatherFragment : Fragment() {
private lateinit var mWeatherModel: WeatherViewModel
@Inject
internal lateinit var viewModelFactory: ViewModelProvider.Factory
....
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mWeatherModel = ViewModelProviders.of(this, viewModelFactory)
.get(WeatherViewModel::class.java)
...
}
}
尝试使用
mDownloadedWeather.setValue(WeatherUtils.extractValues(weather))
而不是
mDownloadedWeather.postValue(WeatherUtils.extractValues(weather))
因为postValue() 将任务发布到主线程以设置给定值。因此,如果您在主线程中执行了以下代码:
liveData.postValue("a");
liveData.setValue("b");
值 "b" 将首先设置,稍后主线程将用值 "a" 覆盖它。
如果在主线程执行发布任务之前多次调用此方法,则只会调度最后一个值。
没有必要将您的 postValue
更改为 setValue
,因为它是在同一个线程中完成的。这里真正的问题是应该如何设置 Dagger2。
在WeatherFragment.kt中使用
internal lateinit var viewModelFactory: CustomViewModelFactory
而不是
internal lateinit var viewModelFactory: ViewModelProvider.Factory
还需要在你的CustomViewModelFactory.kt的构造函数中添加@Inject 注解。
class CustomViewModelFactory @Inject constructor(
最后,根据您提供的代码,您的 WeatherProvider.kt 根本没有处于 初始化状态 。您可以使用此代码执行此操作:
init {
getFromInternet()
}
我有一个 WeatherRepository class,它调用 WeatherProvider class 开始获取天气。
成功获取天气后,我只是 post 使用 postValue 函数的天气,但是 WeatherRepository class 的 init 块中实时数据的观察者永远不会被调用.
我很困惑,我错过了什么...
任何见解都将非常有帮助。
这是我的存储库和提供程序代码:
class WeatherRepository @Inject constructor(private var weatherDao: WeatherDao, private var weatherProvider: WeatherProvider) {
private fun startFetchWeatherService() {
weatherProvider.startFetchWeatherService()
}
init {
// Control flow always gets to this point
var weather = weatherProvider.getDownloadedWeather()
weather.observeForever { // This observer never gets called
if (it != null) AsyncTask.execute { insertWeather(it) }
}
if (isFetchNeeded()) {
startFetchWeatherService() // Android Studio always execute this line since no data is inserted by observer and fetch is needed
}
}
....
}
class WeatherProvider(private val context: Context) {
private val mDownloadedWeather = MutableLiveData<List<Weather>>()
...
fun getDownloadedWeather(): MutableLiveData<List<Weather>> = mDownloadedWeather
fun getFromInternet() {
...
call.enqueue(object : Callback<WorldWeatherOnline> {
override fun onFailure(call: Call<WorldWeatherOnline>?, t: Throwable?) {} // TODO show error
override fun onResponse(call: Call<WorldWeatherOnline>?, response: Response<WorldWeatherOnline>?) {
if (response != null) {
val weather = response.body()?.data
if (weather != null) {
mDownloadedWeather.postValue(WeatherUtils.extractValues(weather)) // app always gets to this point and WeatherUtils successfully returns the List of weathers full of data
}
}
}
})
}
fun startFetchWeatherService() {
val intentToFetch = Intent(context, WeatherSyncIntentService::class.java)
context.startService(intentToFetch)
}
}
...
// Dependency injection always works
// Here's my dagger2 module (other modules are very simillar to this one)
@Module
class ApplicationModule(private val weatherApplication: WeatherApplication) {
@Provides
internal fun provideWeatherApplication(): WeatherApplication {
return weatherApplication
}
@Provides
internal fun provideApplication(): Application {
return weatherApplication
}
@Provides
@Singleton
internal fun provideWeatherProvider(context: WeatherApplication): WeatherProvider {
return WeatherProvider(context)
}
}
@Singleton
class CustomViewModelFactory constructor(private val weatherRepository: WeatherRepository, private val checklistRepository: ChecklistRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
when {
modelClass.isAssignableFrom(WeatherViewModel::class.java) ->
return WeatherViewModel(weatherRepository) as T
modelClass.isAssignableFrom(ChecklistViewModel::class.java) ->
return ChecklistViewModel(checklistRepository) as T
else ->
throw IllegalArgumentException("ViewModel Not Found")
}
}
}
class WeatherFragment : Fragment() {
private lateinit var mWeatherModel: WeatherViewModel
@Inject
internal lateinit var viewModelFactory: ViewModelProvider.Factory
....
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mWeatherModel = ViewModelProviders.of(this, viewModelFactory)
.get(WeatherViewModel::class.java)
...
}
}
尝试使用
mDownloadedWeather.setValue(WeatherUtils.extractValues(weather))
而不是
mDownloadedWeather.postValue(WeatherUtils.extractValues(weather))
因为postValue() 将任务发布到主线程以设置给定值。因此,如果您在主线程中执行了以下代码:
liveData.postValue("a");
liveData.setValue("b");
值 "b" 将首先设置,稍后主线程将用值 "a" 覆盖它。
如果在主线程执行发布任务之前多次调用此方法,则只会调度最后一个值。
没有必要将您的 postValue
更改为 setValue
,因为它是在同一个线程中完成的。这里真正的问题是应该如何设置 Dagger2。
在WeatherFragment.kt中使用
internal lateinit var viewModelFactory: CustomViewModelFactory
而不是
internal lateinit var viewModelFactory: ViewModelProvider.Factory
还需要在你的CustomViewModelFactory.kt的构造函数中添加@Inject 注解。
class CustomViewModelFactory @Inject constructor(
最后,根据您提供的代码,您的 WeatherProvider.kt 根本没有处于 初始化状态 。您可以使用此代码执行此操作:
init {
getFromInternet()
}