我使用的是MVVM + LiveData + Dagger 2.11,在我的app.On SignInFragment上,单击textview,发送请求到服务器,并在snackbar上显示respopnse。它在第一次单击textview.If时运行良好--我再次单击,它发送请求(在此中间显示snackbar响应消息)和ViewModel MediatorLiveData观察者onChanged方法,称为muliple times.Is -- MediatorLiveData的默认行为?
SignInViewModel.java
public class SignInViewModel extends AndroidViewModel {
@Inject
MediatorLiveData mediatorLiveData;
@Inject
SnackbarMessage mSnackbarTextLiveData = new SnackbarMessage();
@Inject
public SignInViewModel(Application application,SignInRepository signInRepository) {
super(application);
this.signInRepository = signInRepository;
}
public MediatorLiveData<ResendActivationCodeResponse> resendActivationCode(final String phoneNumber, final String countryCode) {
final MutableLiveData<NetworkResponse> connectViaPhoneResponseMutableLiveData = signInRepository.resendActivationCode(phoneNumber, countryCode);
mediatorLiveData.addSource(connectViaPhoneResponseMutableLiveData, new NetworkResponseObserver() {
@Override
public void onSuccess(Object data) {
mediatorLiveData.setValue(data);
}
@Override
public void onBadRequest(Object data, String errorMessage) {
mSnackbarTextLiveData.setValue(errorMessage);
}
@Override
public void onUnAuthorisedError(Object data) {
mSnackbarTextLiveData.setValue(data.toString());
}
@Override
public void onFailure(Object data, String errorMessage) {
mSnackbarTextLiveData.setValue(errorMessage);
}
@Override
public void onNoNetworkAvailable(Object data, String errorMessage) {
mSnackbarTextLiveData.setValue(data.toString());
}
@Override
public void onLoading(Object data) {
}
});
return mediatorLiveData;
}
}SignInFragment.java
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSignInViewModel = ViewModelProviders.of(mActivity, mViewModelFactory).get(SignInViewModel.class);
setupSnackbar();
}
private void setupSnackbar() {
mSignInViewModel.getSnackbarMessage().observe(this, new SnackbarMessage.SnackbarObserver() {
@Override
public void onNewMessage(String snackbarMessage) {
ActivityUtils.showSnackbar(getView(), snackbarMessage);
}
});
}
@OnClick(R.id.resend_activation_code_textview)
public void reSendActivationCode() {
showProgress(true);
final MediatorLiveData<ResendActivationCodeResponse> resendActivationCodeResponseMediatorLiveData = mSignInViewModel.resendActivationCode(mPhoneNumber, mCountryCode);
Observer<ResendActivationCodeResponse> resendActivationCodeResponseObserver = new Observer<ResendActivationCodeResponse>() {
@Override
public void onChanged(@Nullable ResendActivationCodeResponse resendActivationCodeResponse) {
if (resendActivationCodeResponse != null) {
showProgress(false);
ActivityUtils.showSnackbar(getView(), activationCodeResentMessage);
//resendActivationCodeResponseMediatorLiveData.removeObserver(this);
}
}
};
resendActivationCodeResponseMediatorLiveData.observe(PhoneNumberActivationFragment.this, resendActivationCodeResponseObserver);
}发布于 2017-10-27 19:00:10
看起来,每次单击addSource时,您都会使用与不同电话号码相关联的不同LiveData来调用resend_activation_code_textview。这些不同的LiveData源也都与不同的NetworkResponseObservers相关联,称为setValue()。setValue()是更新侦听片段的内容,也是被称为太多次的内容。
我相信这个问题是因为每次点击addSource 时都会调用,而且永远不会删除任何源。
如果您单击resend_activation_code_textview 10次,您的mediatorLiveData将有10个不同的源,而您可能只需要一个。
添加源时,它会对mediatorLiveData执行初始触发器,因此始终至少触发一次setValue()。当10个添加的源中的任何一个被更新时,它也会更新您的mediatorLiveData,并调用setValue()。这取决于signInRepository.resendActivationCode所做的事情,如果它更新了其他10个LiveData源中的任何一个,这将触发多个setValue()调用。
有一个removeSource()方法,您可以调用它来确保每次都不会有多个源,这可能会消除多个onChanged调用。但是对于我认为你想要做的事情有一个内置的解决方案(它在引擎盖下使用MediatorLiveData ) --它是switchMap变换。
switchMap允许您更改LiveData正在侦听的底层源,而无需更新观察者。因此,与单击resend_activation_code_textview 10次和添加10个不同的源不同,您可以使用它,这样每次单击resend_activation_code_textview时,前面的源都将被替换为新的源。
switchMap的示例场景是,您有一个查找userById()的方法。您可以创建一个普通的LiveData来存储用户id,然后使用switchMap转换,以便为当前用户提供另一个LiveData。随着id的更改,当前用户将被交换并更新:
MutableLiveData userIdLiveData = ...;
LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
repository.getUserById(id));
void setUserId(String userId) {
this.userIdLiveData.setValue(userId);
}我觉得你在用电话号码和国家代码做类似的事。这就像你的身份。您将希望创建一个包含电话号码和国家代码的对象,我们将其命名为FullPhoneNumber。然后,您将创建一个LiveData<FullPhoneNumber> phoneNumberLiveData,类似于前面示例中的userIdLiveData。然后:
LiveData<ResendActivationCodeResponse> reactivationLiveData =
Transformations.switchMap(phoneNumberLiveData, currentPhoneNumber ->
signInRepository.resendActivationCode(currentPhoneNumber.getNumber(), currentPhoneNumber.getCountryCode());希望这能帮助你,或者至少指出你的正确方向!
https://stackoverflow.com/questions/46961365
复制相似问题