第二次观察viewmodel returns null in android

Observing viewmodel for the second time returns null in android

在我的 android 应用程序中,我遵循具有 mvvm 模式的架构组件。 我的应用程序进行网络调用以显示天气 information.api 调用是从存储库进行的,该存储库 returns 响应视图模型的实时数据,而我的主 activity.

除了一种情况外,该应用程序工作正常,每当我断开互联网以测试失败案例时,它都会根据需要扩大错误视图

在错误视图中我有一个重试按钮,它使方法调用再次观察视图模型(这个方法也是第一次被 oncreate() 调用,有效)

即使在打开 Internet 并单击侦听 observable.still 的重试按钮后,数据也变为空。

我不知道why.please有人帮忙

存储库

@Singleton public class ContentRepository {

@Inject AppUtils mAppUtils;
private RESTService mApiService;

@Inject public ContentRepository(RESTService mApiService) {
 this.mApiService = mApiService;
}

 public MutableLiveData<ApiResponse<WeatherModel>> getWeatherListData() {
final MutableLiveData<ApiResponse<WeatherModel>> weatherListData = new                     MutableLiveData<>();
  mApiService.getWeatherList().enqueue(new Callback<WeatherModel>() {
  @Override public void onResponse(Call<WeatherModel> call,                          Response<WeatherModel> response) {
    weatherListData.setValue(new ApiResponse<>(response.body()));
  }

  @Override public void onFailure(Call<WeatherModel> call, Throwable t) {
    weatherListData.setValue(new ApiResponse<>(t));
  }
});
return weatherListData;
}
}

VIEWMODEL

public class HomeViewModel extends AndroidViewModel {

private final LiveData<ApiResponse<WeatherModel>> weatherListObservable;

 @Inject public HomeViewModel(Application application, ContentRepository contentRepository) {
super(application);
this.weatherListObservable = contentRepository.getWeatherListData();
}

 public LiveData<ApiResponse<WeatherModel>> getWeatherListObservable() {
return weatherListObservable;
}
}

在 ACTIVITY

中观察方法
private void observeViewModel() {
mHomeViewModel = ViewModelProviders.of(this, mViewModelFactory).get(HomeViewModel.class);
mHomeViewModel.getWeatherListObservable().observe(this, weatherModelApiResponse -> {
  if (weatherModelApiResponse.isSuccessful()) {
    mErrorView.setVisibility(View.GONE);
    mBinding.ivLoading.setVisibility(View.GONE);
    try {
      setDataToViews(weatherModelApiResponse.getData());
    } catch (ParseException e) {
      e.printStackTrace();
    }
  } else if (!weatherModelApiResponse.isSuccessful()) {
    mBinding.ivLoading.setVisibility(View.GONE);
    mDialogUtils.showToast(this, weatherModelApiResponse.getError().getMessage());
    mErrorView.setVisibility(View.VISIBLE);
  }
});
}

重试按钮 ACTIVITY

@Override public void onClick(View v) {
switch (v.getId()) {
  case R.id.btn_retry:
    mErrorView.setVisibility(View.GONE);
    observeViewModel();
    break;
}
}

更新:- 2017 年 12 月 5 日

我有幸在 Google 印度开发者日遇到 Lyla Fujiwara,我问了她同样的问题。她向用户 Transformations.switchMap() 推荐了我。以下是更新的解决方案-

@Singleton
public class SplashScreenViewModel extends AndroidViewModel {
  private final APIClient apiClient;
  // This is the observable which listens for the changes
  // Using 'Void' since the get method doesn't need any parameters. If you need to pass any String, or class
  // you can add that here
  private MutableLiveData<Void> networkInfoObservable;
  // This LiveData contains the information required to populate the UI
  private LiveData<Resource<NetworkInformation>> networkInformationLiveData;

  @Inject
  SplashScreenViewModel(@NonNull APIClient apiClient, @NonNull Application application) {
    super(application);
    this.apiClient = apiClient;

    // Initializing the observable with empty data
    networkInfoObservable = new MutableLiveData<Void>();
    // Using the Transformation switchMap to listen when the data changes happen, whenever data 
    // changes happen, we update the LiveData object which we are observing in the MainActivity.
    networkInformationLiveData = Transformations.switchMap(networkInfoObservable, input -> apiClient.getNetworkInformation());
  }

  /**
   * Function to get LiveData Observable for NetworkInformation class
   * @return LiveData<Resource<NetworkInformation>> 
   */
  public LiveData<Resource<NetworkInformation>> getNetworkInfoObservable() {
    return networkInformationLiveData;
  }

  /**
   * Whenever we want to reload the networkInformationLiveData, we update the mutable LiveData's value
   * which in turn calls the `Transformations.switchMap()` function and updates the data and we get
   * call back
   */
  public void setNetworkInformation() {
    networkInfoObservable.setValue(null);
  }
}

Activity 的代码将更新为 -

final SplashScreenViewModel splashScreenViewModel =
  ViewModelProviders.of(this, viewModelFactory).get(SplashScreenViewModel.class);
observeViewModel(splashScreenViewModel);
// This function will ensure that Transformation.switchMap() function is called
splashScreenViewModel.setNetworkInformation();

目前这对我来说是最突出和最合适的解决方案,如果以后有更好的解决方案,我会更新答案。

看着她 droidCon NYC video for more information on LiveData. The official Google repository for LiveData is https://github.com/googlesamples/android-architecture-components/ 寻找 GithubBrowserSample 项目。

旧代码

我还没有找到合适的解决方案,但到目前为止这个方法有效 - 在 observeViewModel() 之外声明 ViewModel 并像这样更改函数 -

private void observeViewModel(final HomeViewModel homeViewModel) {
homeViewModel.getWeatherListObservable().observe(this, weatherModelApiResponse -> {
  if (weatherModelApiResponse.isSuccessful()) {
    mErrorView.setVisibility(View.GONE);
    mBinding.ivLoading.setVisibility(View.GONE);
    try {
      setDataToViews(weatherModelApiResponse.getData());
    } catch (ParseException e) {
      e.printStackTrace();
    }
  } else if (!weatherModelApiResponse.isSuccessful()) {
    mBinding.ivLoading.setVisibility(View.GONE);
    mDialogUtils.showToast(this, weatherModelApiResponse.getError().getMessage());
    mErrorView.setVisibility(View.VISIBLE);
  }
});
}

HomeViewModel 更新为 -

public class HomeViewModel extends AndroidViewModel {

private final LiveData<ApiResponse<WeatherModel>> weatherListObservable;

@Inject public HomeViewModel(Application application, ContentRepository contentRepository) {
super(application);
getWeattherListData();
}

public void getWeatherListData() {
this.weatherListObservable = contentRepository.getWeatherListData();
}
public LiveData<ApiResponse<WeatherModel>> getWeatherListObservable() {
return weatherListObservable;
}

}

现在重试按钮,再次调用observeViewModel函数并将mHomeViewModel传递给它。现在你应该可以得到回应了。