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 -> { register(); }); private void register() { if (!GenericMethods.checkInputField(mKadi) || !GenericMethods.checkInputField(mEmail) || !GenericMethods.checkInputField(mPAss)) { Toast.makeText(this, "Alanlar boş geçilemez", 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(); }
Advertisement
Answer
Because the “register” function creates a new observer everytime it gets called. This is the observer:
Observer<String> signupDataObserver = status -> { 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<String> signupDataObserver = status -> { Toast.makeText(RegisterActivity.this, status, Toast.LENGTH_SHORT).show(); mViewModel.signupData.removeObserver(signupDataObserver); } mViewModel.signupData.observe(this, signupDataObserver);