6

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

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

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

即使在打开互联网后,点击监听 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;
}
}

视图模型

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

在活动中观察方法

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

活动中的重试按钮

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

1 回答 1

8

更新时间:- 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);
  }
}

活动的代码将更新为 -

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 视频,了解有关 LiveData 的更多信息。LiveData 的官方 Google 存储库是https://github.com/googlesamples/android-architecture-components/查找GithubBrowserSample项目。

旧代码

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

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给它。现在您应该能够得到响应。

于 2017-11-28T06:53:28.220 回答