android - android中第二次观察viewmodel返回null

标签 android android-livedata android-architecture-components android-viewmodel

在我的 android 应用程序中,我遵循具有 mvvm 模式的架构组件。 我的应用程序进行网络调用以显示天气信息。api 调用是从存储库进行的,该存储库将响应的实时数据返回到 View 模型,而我的主要 Activity 又观察到它。

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

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

即使在打开 Internet 并单击监听 observable 的重试按钮后,数据仍然变为空。

我不知道为什么,请大家帮忙

存储库

@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;
}
}

View 模型

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 日

有幸遇见Lyla Fujiwara ,在印度的 Google 开发者日期间,我问了她同样的问题。她向用户推荐了 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有关 LiveData 的更多信息。 LiveData 的官方 Google 存储库是 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 传递给它。现在您应该能够得到响应。

关于android - android中第二次观察viewmodel返回null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46627624/

相关文章:

java - 如果我将空值传递给方法,应用程序会因空指针异常而崩溃

android - 哪个是组合多个 LiveData 的更好方法 : using MediatorLiveData or switchMap?

android - 如何使用具有相同 Fragment 的 4 个简单 ViewModel?

android - 如何处理 onResume 中的 LiveData 项目 - 仅限 onPause 状态?

android - 安卓日历

android - 在我的特定情况下唯一识别设备

android - 为什么这个 Android Room 插件不起作用?

android - 即使添加 InstantTaskExecutorRule 后,android.os.Looper 中的方法 getMainLooper 未被模拟仍然发生

android - 如何在支持 SavedStateHandle 的 AndroidViewModel 中注入(inject)依赖项?

Android espresso 错误未找到测试