首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MVVM MediatorLiveData观测器被多次调用

MVVM MediatorLiveData观测器被多次调用
EN

Stack Overflow用户
提问于 2017-10-26 18:27:32
回答 1查看 3.7K关注 0票数 2

我使用的是MVVM + LiveData + Dagger 2.11,在我的app.On SignInFragment上,单击textview,发送请求到服务器,并在snackbar上显示respopnse。它在第一次单击textview.If时运行良好--我再次单击,它发送请求(在此中间显示snackbar响应消息)和ViewModel MediatorLiveData观察者onChanged方法,称为muliple times.Is -- MediatorLiveData的默认行为?

SignInViewModel.java

代码语言:javascript
复制
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

代码语言:javascript
复制
@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);
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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的更改,当前用户将被交换并更新:

代码语言:javascript
复制
MutableLiveData userIdLiveData = ...;
 LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
     repository.getUserById(id));

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

我觉得你在用电话号码和国家代码做类似的事。这就像你的身份。您将希望创建一个包含电话号码和国家代码的对象,我们将其命名为FullPhoneNumber。然后,您将创建一个LiveData<FullPhoneNumber> phoneNumberLiveData,类似于前面示例中的userIdLiveData。然后:

代码语言:javascript
复制
LiveData<ResendActivationCodeResponse> reactivationLiveData = 
Transformations.switchMap(phoneNumberLiveData, currentPhoneNumber ->
     signInRepository.resendActivationCode(currentPhoneNumber.getNumber(), currentPhoneNumber.getCountryCode());

希望这能帮助你,或者至少指出你的正确方向!

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46961365

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档