在 MutableLiveData.observe() 内部工作的 Toast 消息会重复显示。

huangapple go评论83阅读模式
英文:

Toast message inside MutableLiveData.observe() working repeatedly

问题

我有一个注册表单,我想根据是否成功注册向用户显示消息。我将该消息存储在我的视图模型中,该模型具有一个可变的 LiveData 对象来存储该消息,并从我的活动中观察该对象。我的问题是,当我第一次点击注册按钮时,它正常工作,如预期地显示带有我的消息的 Toast,但是当我再次点击该按钮时,Toast 消息会显示两次。我真的不明白我的代码有什么问题。以下是我的代码。

RegisterActivity

mViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(RegisterActivityViewModel.class);
mRegisterBtn.setOnClickListener(v -> {
    register();
});

private void register() {
    if (!GenericMethods.checkInputField(mKadi) || !GenericMethods.checkInputField(mEmail)
            || !GenericMethods.checkInputField(mPAss)) {
        Toast.makeText(this, "Fields cannot be empty", Toast.LENGTH_SHORT).show();
        return;
    }
    signup();
}

private void signup() {
    kAdi = mKadi.getText().toString().trim();
    email = mEmail.getText().toString().trim();
    parola = mPAss.getText().toString().trim();
    parolaTekrari = mValidpass.getText().toString().trim();
    il = mIlTv.getText().toString().trim();
    ilce = mIlceTv.getText().toString().trim();
    getRadioValue(mRadioGroup);
    üniversite = mUniTv.getText().toString().trim();
    User user = new User(kAdi, email, parola, cinsiyet, il, ilce, üniversite);
    mViewModel.signup(user);
    mViewModel.signupData.observe(this, status -> {
        Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
    });
}

RegisterActivityViewModel

public MutableLiveData<String> signupData = new MutableLiveData<>();

private String statusString = null;

public void fetchFromRemote() {
    isLoading.setValue(true);
    disposable.add(RetroService.getInstance().getIller()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableSingleObserver<List<Response>>() {
                @Override
                public void onSuccess(@NonNull List<Response> responses) {
                    isLoading.setValue(false);
                    adresList.setValue(responses);
                }

                @Override
                public void onError(@NonNull Throwable e) {
                    isLoading.setValue(false);
                }
            }));
}

public void signup(User user) {
    Repo.getInstance().signup(user)
            .enqueue(new Callback<Void>() {
                @Override
                public void onResponse(Call<Void> call, retrofit2.Response<Void> response) {

                    if (response.code() == 200) {
                        statusString = "Success!";
                    } else if (response.code() == 400) {
                        statusString = "email already exists";
                    }
                    signupData.setValue(statusString);
                }

                @Override
                public void onFailure(Call<Void> call, Throwable t) {
                    signupData.setValue(t.getMessage());
                }
            });

}

@Override
protected void onCleared() {
    super.onCleared();
    disposable.clear();
}
英文:

I have a register form and ı want to show a message to the user based on signed up successfully or not.I store that message in my view model which has a mutable live data object to store that message and observing that object from my activity.My problem is when ı click to the register button first time it works normally,showing Toast with my message as expected but when ı click that button again Toast message show my message two times.I really didn't understand what's wrong with my code.Here is my code.

RegisterActivity

  mViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(RegisterActivityViewModel.class);
mRegisterBtn.setOnClickListener(v -&gt; {
register();
}); 
private void register() {
if (!GenericMethods.checkInputField(mKadi) || !GenericMethods.checkInputField(mEmail)
|| !GenericMethods.checkInputField(mPAss)) {
Toast.makeText(this, &quot;Alanlar boş ge&#231;ilemez&quot;, Toast.LENGTH_SHORT).show();
return;
}
signup();
}
private void signup(){
kAdi = mKadi.getText().toString().trim();
email = mEmail.getText().toString().trim();
parola = mPAss.getText().toString().trim();
parolaTekrari = mValidpass.getText().toString().trim();
il=mIlTv.getText().toString().trim();
ilce=mIlceTv.getText().toString().trim();
getRadioValue(mRadioGroup);
&#252;niversite=mUniTv.getText().toString().trim();
User user = new User(kAdi,email,parola,cinsiyet,il,ilce,&#252;niversite);
mViewModel.signup(user);
mViewModel.signupData.observe(this,status -&gt;{
Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
});
}

RegisterActivityViewModel

public MutableLiveData&lt;String&gt; signupData = new MutableLiveData&lt;&gt;();
private String statusString=null;
public void fetchFromRemote() {
isLoading.setValue(true);
disposable.add(RetroService.getInstance().getIller()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver&lt;List&lt;Response&gt;&gt;() {
@Override
public void onSuccess(@NonNull List&lt;Response&gt; responses) {
isLoading.setValue(false);
adresList.setValue(responses);
}
@Override
public void onError(@NonNull Throwable e) {
isLoading.setValue(false);
}
}));
}
public void signup(User user) {
Repo.getInstance().signup(user)
.enqueue(new Callback&lt;Void&gt;() {
@Override
public void onResponse(Call&lt;Void&gt; call, retrofit2.Response&lt;Void&gt; response) {
if (response.code() == 200) {
statusString=&quot;Success!&quot;;
} else if (response.code() == 400) {
statusString=&quot;email already exists&quot;;
}
signupData.setValue(statusString);
}
@Override
public void onFailure(Call&lt;Void&gt; call, Throwable t) {
signupData.setValue(t.getMessage());
}
});
}
@Override
protected void onCleared() {
super.onCleared();
disposable.clear();
}

答案1

得分: 1

因为每次调用“register”函数都会创建一个新的观察者。这就是该观察者:

Observer<String> signupDataObserver = status -> {
    Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
}

每次按钮被点击时,该函数会在MutableLiveData“signUpData”上添加一个新的观察者:

mViewModel.signupData.observe(this, signupDataObserver);

因此,如果将“observe”函数移到“OnCreateView”事件中,问题应该可以解决,因为在创建视图时,片段只会注册1个观察者,而不是在按钮被点击时注册。另一个选项是在弹出消息传递后删除观察者:

Observer<String> signupDataObserver = status -> {
    Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
    mViewModel.signupData.removeObserver(signupDataObserver);
}

mViewModel.signupData.observe(this, signupDataObserver);
英文:

Because the "register" function creates a new observer everytime it gets called. This is the observer:

Observer&lt;String&gt; signupDataObserver = status -&gt; {
Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
}

Everytime the button get clicked the function add a new observer on the MutableLiveData "signUpData":

mViewModel.signupData.observe(this, signupDataObserver);

So if you move the "observe" function into the "OnCreateView" event the problem should be solved, because the fragment will register only 1 observer when the view gets created and not when the button gets clicked. Another option would be to delete the observer after the toast message has been delivered:

Observer&lt;String&gt; signupDataObserver = status -&gt; {
Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show();
mViewModel.signupData.removeObserver(signupDataObserver);
}
mViewModel.signupData.observe(this, signupDataObserver);

huangapple
  • 本文由 发表于 2020年10月23日 23:42:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/64503165.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定