我在我的应用程序上使用MVVM + LiveData + Dagger 2.11。在SignInFragment上,单击textview将请求发送到服务器,并在小吃栏上显示respopnse。第一次单击textview时,它可以正常工作。如果再次单击,它会发送请求(在此处显示点心栏响应消息)和ViewModel MediatorLiveData观察者onChanged方法(称为muliple times)。这是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);
    }

最佳答案

似乎您每次单击addSource时都在呼叫带有不同电话号码的不同LiveDataresend_activation_code_textview。这些不同的LiveData源也都与称为NetworkResponseObservers的不同setValue()相关联。 setValue()是什么会更新您的听力片段,这就是所谓的太多次了。

我认为问题是因为每次单击resend_activation_code_textview时都调用addSource,并且从不删除任何源。

如果单击10次,则您的resend_activation_code_textview将有10种不同的来源,而您可能只想使用一种。

添加源后,它会触发mediatorLiveData的初始触发,因此您将始终至少触发一次mediatorLiveData。当10个添加的源中的任何一个更新时,它也会更新您的setValue(),并调用mediatorLiveData。根据setValue()的操作以及是否更新其他10个LiveData源中的任何一个,这将触发一次单击的多个signInRepository.resendActivationCode调用。



您可以调用一个removeSource()方法,以确保您一次不会拥有多个源,这可能会消除多个onChanged调用。但是对于我想您要尝试执行的操作,有一个内置的解决方案(它在后台使用MediatorLiveData)-是switchMap Transformation

setValue()允许您更改switchMap正在侦听的基础源,而无需更新观察者。因此,您无需单击LiveData 10次并添加10个不同的源,而是每次单击resend_activation_code_textview时,以前的源将被替换为新的源。

resend_activation_code_textview的示例方案是您有一种查找switchMap的方法。您制作一个普通的LiveData来存储用户ID,然后使用userById()转换,以便为当前用户使用另一个LiveData。随着id的更改,当前用户被换出并更新:

MutableLiveData userIdLiveData = ...;
 LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
     repository.getUserById(id));

 void setUserId(String userId) {
      this.userIdLiveData.setValue(userId);
 }


我认为您正在使用电话号码和国家/地区代码进行类似操作。这就像您的“身份证”。您将要创建一个包含电话号码和国家/地区代码的对象,我们将其称为switchMap。然后,您将创建一个FullPhoneNumber,与上一个示例中的LiveData<FullPhoneNumber> phoneNumberLiveData相似。然后:

LiveData<ResendActivationCodeResponse> reactivationLiveData =
Transformations.switchMap(phoneNumberLiveData, currentPhoneNumber ->
     signInRepository.resendActivationCode(currentPhoneNumber.getNumber(), currentPhoneNumber.getCountryCode());


希望对您有所帮助或至少为您指明正确的方向!

07-28 03:46